一、数据库瓶颈
数据库并发请求或者慢查询过多,都会导致数据库可用连接数降低,表现为CPU、IO或内存使用率飙升,严重会导致整个数据库不可用。常见场景如下:报表下载导致查询的数据过多
查询需要多个表连接
SQL中包含了大量的函数和排序等增加了CPU运算
查询大表扫描了过多的行数据导致CPU使用率飙升
数据库瞬时请求量过多导致吞吐量下降
SQL中的函数、分页、排序等操作可以优化SQL解决,但是单表数据行过多、数据库并发量过大等问题通过优化的效果甚微,只能通过分库分表来解决。
二、分库分表
常用的方法是垂直拆分和水平拆分。
垂直拆分
垂直拆分是将一个大表(库)拆分成多个不同结构的小表(库)。
分表
一般是把一个表的多个字段按照是否常用、字段长度来拆分到不同的表。这种在设计表的时候就会考虑。避免记录占用空间过大会导致跨页,造成额外的性能开销。
分库
根据业务耦合性将关联度高的表存储在相同的库中。主要是为了解决单台数据库的并发请求过多,导致数据库性能下降的问题。
优点
不同系统可以使用不同的库表,解决业务系统层面的耦合,业务清晰
分摊了高并发场景下单机硬件的IO、数据库连接数
缺点
增加了连表、连库查询的难度
增加了分布式事务的难度
水平拆分
垂直拆分依然解决不了单表数据量过多的问题,水平拆分是将一个大表(库)按照一定规则拆分到不同的表(库),每个表(库)都是部分数据,分布式存储数据。
库内分表
按照某种规则将数据分布到多个表中,主要是为了解决单表数据量过大而查询缓慢。但是库内分表只解决单表数据量过大问题,但没有将表分布到不同机器上,所以对于减轻MySQL压力帮助不大。
分库分库
水平的分库其实就是把拆分的表放到不同的机器库上。
优点
不存在单表数据量过多的问题
将单个数据库的压力分摊到了不同的机器
缺点
增加了多库联合查询的难度
出现了跨库的事务问题
拆分策略
根据数据范围,例如:ID范围、时间范围等 根据数据取模,例如:用户ID取模、商户ID取模、记录ID取模等。
三、中间件类型
知名的分库分表中间件分为两类:
client模式:Sharding-sphere、TDDL
proxy模式:Atlas、MyCat
两种模式的核心步骤都是:SQL解析,重写,路由,执行,结果归并。
四、多分区字段方案
sharding column的选取是分库分表的第一步,一般会选业务强相关的属性,但是实际业务往往存在多个sharding cloumn,以下以交易订单为例:冗余全量
冗余关系索引
五、迁移
停机迁移
凌晨停机,使用迁移程序将旧库的数据写入到中间件中,依靠中间件进行数据分发存储,最后修改程序配置连接到中间件。不停机迁移
重点是要平稳、无感知的完成数据迁移,一般会采用双写方案。上线双写,同时写入旧库和新库的中间件
历史数据离线迁移到新库
将读请求路由到新库
清理旧的数据、代码和资源释放
以上每个节点执行完后都需要校验数据的一致性,详细流程如下:
DTS完成全量数据同步并开启增量同步
校验新旧库数据的一致性
将读请求路由到新库,在用户角度校验数据的正确性
将写请求路由到新库,同时关闭增量同步
六、扩容
针对已有分库分表的场景,随着业务的发展扩容势在必行。常用的方式有升级从库和双写从库。 升级从库- uid%4=0 和 uid%4=2 的分别指向A0和A,也就是之前指向uid%2=0的数据分裂为uid%4=0和uid%4=2
- uid%4=1 和 uid%4=3 的分别指向B0和B,也就是之前指向uid%2=1的数据分裂为uid%4=1和uid%4=3
因为A和A0的数据相同,B和B0的数据相同,所以无需做数据迁移即可,只需要变更一下分库(表)配置即可无需重启。
修改分片配置,做好新库和旧库的映射
同步配置,从库升级为主库
解除主从关系 冗余数据清理
为新的数据节点搭建新的从库
双写从库
双写的核心是增加数据库,同时写两份数据。新增双写
新旧数据迁移
- 数据修正
分库配置修改
- 清理数据
C库和A库都包含对方一半的数据,需要清除冗余的对方的数据 D库和B库都包含对方一半的数据,需要清除冗余的对方的数据