对于咱们经常使用的分库分表方案来讲,有很大的优点,分库分表的扩容是一件头疼的问题,若是采用对db层作一致性hash,或是中间价的支持,它的成本过于高昂了,若是不如此,只能停机维护来处理,对高可用性会产生影响。算法
那是否有方案,既能够快速扩展,又不下降可用性?这一篇,咱们聊聊分库分表的扩展方案,供你们一块儿探讨。数据库
为了增长db的并发能力,常见的方案就是对数据进行sharding,也就是常说的分库分表,这个须要在初期对数据规划有一个预期,从而预先分配出足够的库来处理。安全
好比目前规划了3个数据库,基于uid进行取余分片,那么每一个库上的划分规则以下:服务器
如上咱们能够看到,数据能够均衡的分配到3个数据库里面。网络
可是,若是后续业务发展的速度很快,用户量数据大量上升,当前容量不足以支撑,应该怎么办?并发
须要对数据库进行水平扩容,再增长新库来分解。新库加入以后,原先sharding到3个库的数据,就能够sharding到四个库里面了工具
不过此时因为分片规则进行了变化(uid%3 变为uid%4),大部分的数据,没法命中在原有的数据库上了,须要从新分配,大量数据须要迁移。ui
好比以前uid1经过uid1%3 分配在A库上,新加入库D以后,算法改成uid1%4 了,此时有可能就分配在B库上面了。若是你有看到以前《一致性哈希的原理与实践》,就会发现新增一个节点,大概会有90%的数据须要迁移,这个对DB同窗的压力仍是蛮大的,那么如何应对?blog
通常有如下几种方式。开发
停服迁移是最多见的一种方案了,通常以下流程:
预估停服时间,发布停服公告
停服,经过事先作好的数据迁移工具,按照新的分片规则,进行迁移
修改分片规则
启动服务
咱们看到这种方式比较安全,停服以后没有数据写入,可以保证迁移工做的正常进行,没有一致性的问题。惟一的问题,就是停服了和时间压力了。
停服,伤害用户体验,同时也下降了服务器的可用性
必须在制定时间内完成迁移,若是失败,须要择日再次进行。同时增长了开发人员的压力,容易发生大的事故
数据量的巨大的时候,迁移须要大量时间
那有没有其余方式来改进一下,咱们看下如下两种方案。
线上数据库,咱们为了保持其高可用,通常都会每台主库配一台从库,读写在主库,而后主从同步到从库。以下,A,B是主库,A0和B0是从库。
此时,当须要扩容的时候,咱们把A0和B0升级为新的主库节点,如此由2个分库变为4个分库。同时在上层的分片配置,作好映射,规则以下:
uid%4=0和uid%4=2的分别指向A和A0,也就是以前指向uid%2=0的数据,分裂为uid%4=0和uid%4=2
uid%4=1和uid%4=3的指向B和B0,也就是以前指向uid%2=1的数据,分裂为uid%4=1和uid%4=3
由于A和A0库的数据相同,B和B0数据相同,因此此时无需作数据迁移便可。只须要变动一下分片配置便可,经过配置中心更新,无需重启。
因为以前uid%2的数据分配在2个库里面,此时分散到4个库中,因为老数据还存在(uid%4=0,还有一半uid%4=2的数据),因此须要对冗余数据作一次清理。
而这个清理,不会影响线上数据的一致性,但是随时随地进行。
处理完成之后,为保证高可用,以及下一步扩容需求。能够为现有的主库再次分配一个从库。
总结一下此方案步骤以下:
修改分片配置,作好新库和老库的映射。
同步配置,从库升级为主库
解除主从关系
冗余数据清理
为新的数据节点搭建新的从库
双写的方案,更多的是针对线上数据库迁移来用的,固然了,对于分库的扩展来讲也是要迁移数据的,所以,也能够来协助分库扩容的问题。
原理和上述相同,作分裂扩容,只是数据的同步方式不一样了。
1.增长新库写连接
双写的核心原理,就是对须要扩容的数据库上,增长新库,并对现有的分片上增长写连接,同时写两份数据。
由于新库的数据为空,因此数据的CRUD对其没有影响,在上层的逻辑层,仍是以老库的数据为主。
2.新老库数据迁移
经过工具,把老库的数据迁移到新库里面,此时能够选择同步分裂后的数据(1/2)来同步,也能够全同步,通常建议全同步,最终作数据校检的时候好处理。
3.数据校检
按照理想环境状况下,数据迁移以后,由于是双写操做,因此两边的数据是一致的,特别是insert和update,一致性状况很高。但真实环境中会有网络延迟等状况,对于delete状况并非很理想,好比:
A库删除数据a的时候,数据a正在迁移,尚未写入到C库中,此时C库的删除操做已经执行了,C库会多出一条数据。
此时就须要作好数据校检了,数据校检能够多作几遍,直到数据几乎一致,尽可能以旧库的数据为准。
4.分片配置修改
数据同步完毕,就能够把新库的分片映射从新处理了,仍是按照老库分裂的方式来进行,
u以前uid%2=0,变为uid%4=0和uid%4=2的
uid%2=1,变为uid%4=1和uid%4=3的。