提笔忘字

数据库分库分表

分库分表在解决如 IO 瓶颈、读写性能、物理存储瓶颈、内存瓶颈、单机故障影响面等问题的同时,也带来如事务性、主键冲突、跨库 join、跨库聚合查询等问题。

在综合业务场景考虑,正如缓存的使用一样,本着非必须勿使用原则。如数据库确实成为性能瓶颈时,在设计分库分表方案时也应充分考虑方案的扩展性,或者考虑采用成熟热门的分布式数据库解决方案。

什么是分库分表

分库:将一个数据库中的数据按照某种规则分拆到多个数据库中,以缓解单服务器的压力(CPU、内存、磁盘、IO)。

分表:将一个表中的数据按照某种规则分拆到多张表中,降低锁粒度以及索引树,提升数据查询效率。

为什么分库分表

性能角度:CPU、内存、磁盘、IO瓶颈;随着业务体量扩大,数据规模达到百万行,数据库索引树庞大,查询性能出现瓶颈;用户并发流量规模扩大,由于单库(单服务器)物理性能限制也无法承载大流量。

可用性角度:单机故障率影响面;如果是单库,数据库宕机会导致100%服务不可用,N 库则可以将影响面降低 N 倍。

分库分表带来的问题

事务性问题:分库可能导致执行一次事务所需的数据分布在不同服务器上,数据库层面无法实现事务性操作,需要更上层业务引入分布式事务操作,难免会给业务带来一定复杂性。

主键(自增 ID)唯一性问题:在数据库表设计时,经常会使用自增ID作为数据主键,这就导致后续在迁库迁表或者分库分表操作时,会因为主键的变化或者主键不唯一产生冲突。

跨库多表 join 问题:join 操作往往会给后续的分库分表操作带来各种问题,可能导致数据的死锁。

跨库聚合查询问题:分库分表会导致常规聚合查询操作,如group byorder by等变得异常复杂。

什么是好的分库分表方案

满足业务场景需要:根据业务场景的不同选择不同分库分表方案,比如按照时间划分、按照用户ID划分、按照业务能力划分等。

方案可持续性:业务数据量级和流量量级未来进一步达到新的量级的时候,我们的分库分表方案可以持续灵活扩容处理。

最小化数据迁移:扩容时一般涉及到历史数据迁移,其扩容后需要迁移的数据量越小其可持续性越强,理想的迁移前后的状态是(同库同表 > 同表不同库 > 同库不同表 > 不同库不同表)。

最小化数据偏斜:数据在库表中分配的均衡性,尽可能保证数据流量在各个库表中保持等量分配,避免热点数据对于单库造成压力;最大数据偏斜率=(数据量最大样本-数据量最小样本)/数据量最小样本,一般来说,如果我们的最大数据偏斜率在5%以内是可以接受的。

如何分库分表

垂直拆分

垂直拆表:即大表拆小表,将一张表中数据不同“字段”分拆到多张表中,比如商品库将商品基本信息、商品库存、卖家信息等分拆到不同库表中;考虑因素有将不常用的、数据较大、长度较长(比如 text 类型字段)的拆分到“扩展表“,表和表之间通过”主键外键“进行关联;好处是降低表数据规模,提升查询效率,也避免查询时数据量太大造成的“跨页”问题。

垂直拆库:在垂直拆表的基础上,将一个系统中的不同业务场景进行拆分,比如订单表、用户表、商品表;好处是降低单数据库服务的压力(物理存储、内存、IO等)、降低单机故障的影响面。

水平拆分

将总体数据按照某种维度(时间、用户)等分拆到多个库中或者表中,如订单按照(日期、用户ID、区域)分库分表。

水平拆表:将数据按照某种维度拆分为多张表,但是由于多张表还是从属于一个库,其降低锁粒度,一定程度提升查询性能,但是仍然会有 IO 性能瓶颈。

水平拆库:将数据按照某种维度分拆到多个库中,降低单机单库的压力,提升读写性能。

#Database