分库分表后的平滑扩容
Last updated
Last updated
数据库架构演进过程:
其中,双Master方案:当主库挂掉的时候,虚ip自动漂移到另一个主库,整个过程对调用方透明,可以保证数据库的高可用。
在根据Hash取模的方案进行水平分库分表后,扩容其实是一件非常麻烦的事。如果是采用其他路由规则,比如按时间/范围/城市等,则很简单,直接加库就可以。
假设原来分了x个库,现在要扩展到y个库,则实施方案如下:
(1)站点挂一个公告“为了为广大用户提供更好的服务,本站点/游戏将在今晚00:00-2:00之间升级,届时将不能登录,用户周知”
(2)停服务
(3)新建y个库,做好高可用
(4)数据迁移,重新分布,写一个数据迁移程序,从x个库里导入到y个库里,路由规则由%x升级为%y
(5)修改服务配置,原来x行配置升级为y行
(6)重启服务,连接新库重新对外提供服务
整个过程中,最耗时的是第四步数据迁移。
回滚方案:如果数据迁移失败,或者迁移后测试失败,则将配置改回x库,恢复服务,改天再挂公告。
方案优点:简单
方案缺点:
(1)停服务,不高可用
(2)技术同学压力大,所有工作要在规定时间内做完,根据经验,压力越大约容易出错(这一点很致命)
(3)如果有问题第一时间没检查出来,启动了服务,运行一段时间后再发现有问题,难以回滚,需要回档,可能会丢失一部分数据
有没有更平滑的方案呢?
假设原来分2个库,现在要扩为4个库,实施方案如下:
第一步:修改配置
a)数据库实例所在的机器做双虚ip,原来%2=0的库是虚ip0,现在增加一个虚ip00,%2=1的库时ip1,现在增加一个虚ip11;
b)修改应用(数据库使用方)的数据库配置(保证拆分后依然能够路由到正确的数据),如下图所示:
将2个库的数据库配置,改为4个库的数据库配置
%4=0与%4=2的数据落在原来%2=0所在的库,%4=1与%4=3的数据落在原来%2=1所在的库
服务层reload配置,reload可能是这么几种方式:
a)比较原始的,重启服务,读新的配置文件
b)高级一点的,配置中心给服务发信号,重读配置文件,重新初始化数据库连接池
不管哪种方式,reload之后,数据库的实例扩容就完成了,原来是2个数据库实例提供服务,现在变为4个数据库实例提供服务,这个过程一般可以在秒级完成。
整个过程可以逐步重启,对服务的正确性和可用性完全没有影响:
a)即使%2寻库和%4寻库同时存在,也不影响数据的正确性,因为此时仍然是双主数据同步的
b)服务reload之前是不对外提供服务的,冗余的服务能够保证高可用
第三步:数据收缩
a)把双虚ip修改回单虚ip;
b)解除旧的双主同步,让成对库的数据不再同步增加;
d)删除掉冗余数据(对应上图,就是user0-master1中删除%4=2的数据,user0-master2中删除%4=0的数据,user1-master1中删除%4=3的数据,user1-master2中删除%4=1的数据)
这样下来,每个库的数据量就降为原来的一半,数据收缩完成。
该方案能够实现n库扩2n库的秒级、平滑扩容,增加数据库服务能力,降低单库一半的数据量。
总结步骤:对原来的每个分表,双主均做双虚IP,然后修改应用数据库配置以及路由规则,然后先将双虚IP改为单虚IP,解除双主关系,为每个单库增加新的同步主库,最后,删除冗余数据。
内容来源:
数据库秒级平滑扩容架构方案,略有调整,重画了图。
这步操作如下图所示:第二步:reload应用(数据库使用方)配置
c)增加新的双主同步(对应上图,就是为user0-master1/user0-master2/user1-master1/user1-master2分别增加同步主库)