什么情况下去要进行分库分表?
在业务量不大的情况下,通常使用单表在进行操作,但是随着表数据越来越大,性能也越来越差;
mysql单表 qps 2k,树深度3层-4层,大概是单表能承受的相对最大极限;
ps: 本文不讨论分区表;
分表策略
1. rang分表,id、日期等
单表1000,分4个库,4张表
将每个表的初始id确定,0 - 500万, 500 - 1000 ,1000- 1500, 1500 - 2000
插入:服务器每隔一段时间查询当前使用的 表 a (0-500)是 否快要达到临界点(450/ 500),
如果到到达则更新到下一张表 b(500-1000),可以解决边界问题。
查询:根据id就可以分配到不同表即可。
缺点 : 高并发热点数据
在通常业务中,新用户的活跃度是远高于老用户的,意味着热点数据全部分配在同一张表上,存在部分的资源浪费情况;
解决方案:
可购买不同的数据库配置存放;
优点:
分表比较简单,再次扩容只需要添加表就行,不存在迁移;
id 自增生成,不依赖第三方
很适合id自增的表分库分表
2. hash分表
使用第三方的id生成器;比如雪花;
将id通过hash取模分配到不同的表中。
优点: 数据分布均匀,不会出现热点数据在一张表的情况,
缺点: 需要维护一个高可用的id服务(可参考美团高可用雪花生成算法)
线上分表
在线分表最需要在意的问题就是增量数据,无论是rang还是hash都存在这种问题。
在线分表不能像停服更新一样,一次将大量数据挪到新库里,需要批量迁移,防止数据库打死;
为了保证新旧表数据一致,还需要保持双写(新库就库都需要写);
数据迁移:
根据分表规则,一小段一小段的将数据迁移到新库,这个段不能太大,防止数据库被锁死
比如1千万条数据,每次迁移1千条数据;
对每条数据做hash分组,分批次插入,直到出现重复,代表迁移完成;
事务顺序:
锁旧表
批量数据,根据hash分组到4张表
插入新表 <---- 其中 这一步并不会锁新表,
在排除断电等极端情况下,插入失败只会是出现重复,
那么就意味着已经追上最新数据了,就可以停止迁移了
解锁旧表
缺点: 代码实现比较困难,对分布式服务还要考虑旧表何时断开等诸多细节,速度慢。
双写同步:
需要同时向新旧两表插入或修改
事务顺序为:
锁原表
锁新表
写入
解锁原表
解锁新表
情况1:
原表更新成功,新表更新失败。
情况2:
原表更新失败,新表更新失败
如出现情况2,则代表本次更新失败,但是数据是一致的,是可以接受的。
情况1则会出现数据不一致,但是原表更新成功,可以通过数据迁移完成同步,也是可以接受的。