最近做了一个数据库分库分表迁移的项目,从旧的单库单表迁移到新的分库分表架构,踩了很多坑,今天来分享一下实战经验。

最近,我,负责,了,一个,数据库,分库分表,迁移,的,项目,把,旧,的,单库单表,系统,迁移,到,新,的,分库分表,架构,整个,过程,持续,了,几个,月,踩,了,很多,坑,也,积累,了,很多,实战,经验。

今天,这篇,文章,就,来,分享,一下,这次,迁移,的,实战,经验,希望,能,给,正在,做,或者,准备,做,分库分表,迁移,的,朋友,一些,参考。

一、为什么要做分库分表

在,说,迁移,过程,之前,先,说说,为什么,要,做,分库分表,我们,的,系统,是,一个,电商,平台,用户,量,和,订单,量,都,很大,而且,增长,很快,最,开始,的,时候,用,的,是,单库单表,的,MySQL,架构,所有,数据,都,在,一个,库,里,订单,表,已经,有,几千万,条,数据,了,而且,每天,还,在,快速,增长,随着,数据量,的,增长,各种,问题,都,来,了。

首先,是,查询,性能,问题,订单,表,数据量,太,大,即使,加,了,索引,很多,查询,还是,很,慢,尤其是,一些,复杂,的,查询,和,统计,查询,经常,要,几秒,甚至,十几秒,才能,返回,结果,用户,体验,很,差,而且,慢查询,多,了,也,会,占用,数据库,连接,和,资源,影响,其他,正常,的,查询,和,写入,导致,整个,数据库,性能,下降。

其次,是,写入,性能,问题,订单,表,写入,量,很,大,尤其是,大促,的,时候,写入,QPS,很,高,单库单表,的,写入,性能,已经,到,了,瓶颈,经常,出现,写入,延迟,甚至,超时,的,情况,影响,业务,正常,运行,而且,单库单表,的,写入,能力,是,有,上限,的,随着,业务,增长,迟早,会,扛,不住。

还有,是,高可用,和,扩展性,问题,单库单表,的,架构,扩展性,很,差,只能,通过,提升,硬件,配置,来,提升,性能,也就是,纵向,扩展,但是,纵向,扩展,是,有,上限,的,而且,成本,越来越,高,性价比,越来越,低,而且,单库,是,单点,一旦,数据库,出,问题,整个,业务,都,受,影响,高可用,性,差,虽然,可以,做,主从,复制,读写,分离,但是,主库,还是,单点,写入,都,在,主库,主库,出,问题,还是,影响,很大。

基于,这些,问题,我们,决定,做,分库分表,把,单库单表,的,架构,改成,分库分表,的,架构,通过,横向,扩展,来,提升,数据库,的,性能,和,扩展性,分库分表,之后,数据,分散,到,多个,库,和,多个,表,里,每个,库,和,每个,表,的,数据量,都,减小,了,查询,和,写入,性能,都,能,提升,而且,能,横向,扩展,通过,增加,库,和,表,的,数量,来,提升,性能,扩展性,好,很多,也,能,提升,高可用,性,因为,数据,分散,了,一个,库,出,问题,只,影响,部分,数据,不,会,影响,全部。

二、分库分表方案设计

决定,做,分库分表,之后,首先,要,设计,分库分表,的,方案,这,是,最,重要,的,一步,方案,设计,得,好,后面,迁移,和,使用,都,顺利,方案,设计,得,不好,后面,会,很,痛苦,甚至,需要,重新,来。

首先,要,确定,分库分表,的,维度,也就是,按,什么,字段,来,分,我们,的,核心,表,是,订单,表,查询,和,写入,都,主要,是,按,用户ID,或者,订单ID,来,操作,所以,我们,选择,按,用户ID,来,分库分表,因为,大部分,查询,都是,按,用户ID,来,查,某个,用户,的,订单,按,用户ID,分,的话,同一个,用户,的,订单,都,在,同一个,库,同一个,表,里,查询,的,时候,只,需要,查,一个,库,一个,表,性能,好,也,不需要,跨库,查询,很,方便。

但是,按,用户ID,分,也,有,问题,就是,有些,查询,不是,按,用户ID,来,查,的,比如,按,订单ID,查,按,时间,范围,查,统计,查询,等等,这些,查询,按,用户ID,分,的话,就,需要,跨,多个,库,多个,表,查,性能,差,也,很,麻烦,对于,这些,查询,我们,的,方案,是,做,异构,索引,或者,用,搜索引擎,比如,Elasticsearch,来,支持,复杂,查询,和,统计,查询,把,订单,数据,同步,到,ES,里,复杂,查询,和,统计,都,走,ES,不,走,MySQL,MySQL,只,负责,按,用户ID,的,简单,查询,和,写入,这样,就,解决,了,复杂,查询,的,问题。

然后,要,确定,分库分表,的,数量,也就是,分,几个,库,几个,表,这个,要,根据,数据量,和,增长,速度,来,估算,我们,的,订单,表,当时,有,几千万,条,数据,每天,增长,几十万,条,我们,估算,了,一下,未来,3到5年,的,数据量,大概,会,到,几十亿,条,所以,我们,决定,分,8个,库,每个,库,分,32个,表,总共,256个,表,这样,每个,表,的,数据量,大概,在,几百万,到,一千万,左右,查询,性能,比较,好,而且,预留,了,足够,的,扩展,空间,未来,几年,都,不用,再,分,了。

分库分表,的,数量,很,重要,不能,太少,也,不能,太多,太少,的话,很快,又,会,遇到,性能,瓶颈,需要,再次,分库分表,很,麻烦,太多,的话,管理,成本,高,资源,浪费,也,可能,性能,不,一定,好,因为,跨库,查询,的,成本,高,所以,要,根据,实际,情况,合理,估算,选择,合适,的,数量,一般,建议,预留,3到5年,的,扩展,空间,不要,刚,分,完,很快,又,不够,了。

然后,要,确定,分库分表,的,算法,也就是,怎么,根据,用户ID,计算,应该,存,到,哪个,库,哪个,表,我们,用,的,是,取模,算法,也就是,用户ID,对,库,数量,取模,得到,库,索引,用户ID,对,表,数量,取模,得到,表,索引,这种,算法,简单,高效,数据,分布,也,比较,均匀,是,最,常用,的,分库分表,算法,当然,也,有,其他,算法,比如,范围,分片,哈希,分片,一致性,哈希,等等,各有优缺点,要,根据,业务,场景,选择,我们,的,场景,用,取模,就,够,了,简单,高效,也,满足,需求。

还有,要,考虑,主键,的,问题,分库分表,之后,自增ID,就,不能,用,了,因为,每个,表,都,有,自己,的,自增ID,会,重复,所以,需要,用,分布式,唯一,ID,我们,用,的,是,雪花,算法,Snowflake,生成,分布式,唯一,ID,作为,订单,的,主键,雪花,算法,生成,的,ID,是,64位,的,包含,时间戳,机器ID,序列号,等,信息,全局,唯一,而且,趋势,递增,性能,也,很,好,很,适合,作为,分库分表,的,主键,当然,也,可以,用,其他,方案,比如,UUID,但是,UUID,是,字符串,长度,长,无序,性能,差,不,推荐,用,数据库,自增ID,也,可以,但是,需要,单独,的,发号器,比较,麻烦,雪花,算法,是,比较,好,的,方案。

三、迁移方案设计

分库分表,方案,设计,好,之后,就要,设计,迁移,方案,了,也就是,怎么,把,旧,库,的,数据,迁移,到,新,的,分库分表,架构,里,而且,要,保证,迁移,过程,中,业务,不,停,数据,不,丢,不,错,这,是,最,难,的,部分,也是,最,关键,的,部分。

首先,要,确定,迁移,的,策略,是,停机,迁移,还是,不停机,迁移,停机,迁移,简单,但是,需要,停,业务,影响,用户,我们,的,系统,是,电商,平台,不能,随便,停机,所以,我们,选择,的,是,不停机,迁移,也就是,在线,迁移,迁移,过程,中,业务,正常,运行,用户,无感知,这,样,用户,体验,好,但是,技术,难度,大,很多。

不停机,迁移,的,核心,思路,是,双写,加,增量,同步,加,数据,校验,具体,来说,分,几个,阶段:

第一,阶段,是,准备,阶段,搭建,新,的,分库分表,数据库,集群,部署,好,中间件,或者,分库分表,框架,我们,用,的,是,Sharding-JDBC,做,分库分表,的,中间件,客户端,层,的,分库分表,不需要,单独,部署,代理,层,比较,简单,性能,也,好,然后,修改,应用,代码,支持,双写,也就是,写入,的,时候,同时,写,旧库,和,新,的,分库分表,库,查询,还是,走,旧库,这个,阶段,主要,是,让,新,库,有,增量,数据,和,旧库,保持,同步。

第二,阶段,是,全量,迁移,阶段,写,一个,数据,迁移,工具,把,旧库,的,历史,数据,全量,迁移,到,新,的,分库分表,库,里,这个,过程,要,注意,性能,和,对,旧库,的,影响,不能,因为,迁移,数据,把,旧库,搞,挂,了,影响,业务,所以,要,控制,迁移,速度,分批,迁移,比如,每次,迁移,1000条,或者,按,时间,范围,迁移,而且,要,在,业务,低峰,期,迁移,减少,对,业务,的,影响,我们,的,迁移,工具,是,自己,写,的,Java,程序,用,多线程,分批,读取,旧库,数据,按,分库分表,规则,写入,新库,还,支持,断点,续传,迁移,失败,了,能,从,断点,继续,不用,从头,来,很,方便。

第三,阶段,是,增量,同步,和,数据,校验,阶段,全量,迁移,完成,之后,因为,迁移,过程,中,旧库,还,在,写入,新,数据,所以,新库,和,旧库,之间,可能,有,数据,差异,需要,做,增量,同步,把,迁移,过程,中,新,产生,的,数据,同步,到,新库,我们,是,通过,双写,来,保证,增量,数据,同步,的,因为,第一,阶段,就,已经,开,了,双写,所以,新,数据,都,同时,写,到,旧库,和,新库,了,全量,迁移,完成,之后,只,需要,校验,数据,一致性,就,行,了,数据,校验,是,很,重要,的,一步,要,确保,新库,和,旧库,的,数据,完全,一致,没有,丢,数据,也,没有,错,数据,我们,写,了,数据,校验,工具,分批,比对,旧库,和,新库,的,数据,按,用户ID,范围,比对,每条,数据,的,每个,字段,都,比对,确保,完全,一致,如果,有,不一致,的,记录,下来,分析,原因,修复,然后,重新,校验,直到,完全,一致。

第四,阶段,是,切流,阶段,数据,校验,完全,一致,之后,就,可以,切流,了,也就是,把,查询,流量,从,旧库,切,到,新,的,分库分表,库,切流,要,灰度,进行,不要,一下子,全,切,先,切,一小部分,流量,比如,1%,观察,新库,的,性能,和,数据,是否,正常,有没有,问题,没问题,的话,再,逐步,增加,流量,10%,30%,50%,100%,直到,全部,切,到,新库,这个,过程,要,密切,监控,新库,的,各种,指标,比如,QPS,响应,时间,错误率,连接数,CPU,内存,磁盘,等等,一旦,有,异常,立即,回滚,切回,旧库,保证,业务,不,受,影响,我们,的,切流,过程,持续,了,大概,一周,从,1%,慢慢,切,到,100%,中间,没有,出,大,问题,很,顺利。

第五,阶段,是,下线,旧库,阶段,全部,切流,到,新库,之后,观察,一段时间,比如,一到两周,确认,新库,稳定,没有,问题,就,可以,下线,双写,和,旧库,了,先,停,掉,双写,只,写,新库,然后,旧库,保留,一段时间,作为,备份,等,确认,完全,没问题,了,再,下线,旧库,或者,归档,存储,整个,迁移,过程,就,完成,了。

四、遇到的坑和解决方案

整个,迁移,过程,中,遇到,了,很多,坑,下面,说,几个,比较,典型,的,坑,和,我们,的,解决方案。

坑一:全量迁移太慢,影响旧库性能

最,开始,的,时候,我们,的,迁移,工具,写,得,比较,简单,单线程,迁移,速度,很,慢,几千万,条,数据,要,迁,好,几天,而且,迁移,的,时候,对,旧库,的,查询,压力,很,大,影响,了,线上,业务,的,查询,性能,后来,我们,优化,了,迁移,工具,改成,多线程,分批,迁移,按,主键,范围,分批,每批,1000条,多线程,并行,迁移,速度,提升,了,很多,而且,加,了,限速,控制,每秒钟,最多,迁移,多少,条,避免,对,旧库,造成,太,大,压力,还,加,了,业务,高峰,期,自动,暂停,的,功能,在,业务,高峰,期,自动,暂停,迁移,低峰,期,再,继续,这样,就,不会,影响,线上,业务,了,优化,之后,迁移,速度,快,了,很多,也,不,影响,业务,了。

坑二:数据校验不一致

全量,迁移,完成,之后,我们,做,数据,校验,发现,有,一些,数据,不一致,当时,很,紧张,以为,迁移,出,问题,了,后来,仔细,分析,发现,是,因为,迁移,过程,中,这些,数据,在,旧库,被,修改,或者,删除,了,但是,双写,的,时候,新库,的,更新,或者,删除,没有,成功,导致,不一致,原因,是,我们,的,双写,逻辑,有,问题,更新,和,删除,的,时候,没有,正确,处理,分库分表,的,路由,导致,新库,的,更新,删除,失败,后来,我们,修复,了,双写,逻辑,确保,更新,和,删除,也,能,正确,同步,到,新库,然后,重新,迁移,了,不一致,的,数据,再,校验,就,一致,了,这个,坑,告诉,我们,双写,一定,要,处理,好,增删改,所有,操作,不能,只,处理,新增,还要,处理,更新,和,删除,不然,会,有,数据,不一致。

坑三:跨库分页查询问题

切流,之后,我们,发现,一些,分页,查询,性能,很,差,因为,这些,查询,不是,按,用户ID,查,的,需要,跨,多个,库,多个,表,查,然后,在,内存,里,排序,分页,性能,很,差,而且,数据量,大,的话,很,容易,内存,溢出,这,是,分库分表,的,常见,问题,跨库,分页,查询,很难,处理,我们,的,解决方案,是,把,这些,查询,都,改,到,Elasticsearch,里,去,查,把,订单,数据,同步,到,ES,复杂,查询,和,分页,查询,都,走,ES,ES,支持,分布式,搜索,和,聚合,性能,很,好,能,解决,跨库,查询,的,问题,MySQL,只,负责,按,用户ID,的,简单,查询,和,写入,这样,就,解决,了,跨库,分页,查询,的,问题,性能,也,提升,了,很多。

坑四:分布式事务问题

分库分表,之后,原来,的,单库,事务,就,不能,用,了,因为,一个,业务,操作,可能,涉及,多个,库,的,多个,表,需要,分布式,事务,我们,的,订单,创建,流程,就,涉及,订单,表,库存,表,用户,表,等,多个,表,分库分表,之后,这些,表,可能,在,不同,的,库,里,原来,的,本地,事务,就,不,能用,了,需要,分布式,事务,我们,最,开始,想,用,两阶段,提交,2PC,但是,发现,性能,差,而且,有,阻塞,问题,不,适合,高并发,场景,后来,我们,改用,最终,一致性,的,方案,用,消息,队列,加,本地,消息,表,的,方式,保证,最终,一致性,把,一个,大,事务,拆,成,多个,小,事务,通过,消息,异步,处理,保证,最终,数据,一致,虽然,不是,强,一致,但是,对于,电商,场景,最终,一致,就,够,了,性能,也,好,很多,这个,坑,告诉,我们,分库分表,之后,要,重新,考虑,事务,的,处理,尽量,避免,分布式,事务,用,最终,一致性,代替,强,一致性,性能,更,好,也,更,可靠。

坑五:扩容问题

分库分表,之后,我们,遇到,了,扩容,的,问题,也就是,数据量,继续,增长,需要,增加,库,和,表,的,数量,最,开始,我们,用,的,是,取模,分片,扩容,的话,需要,重新,分片,数据,迁移,量,很,大,很,麻烦,后来,我们,研究,了,一下,发现,可以,用,一致性,哈希,或者,倍数,扩容,的,方式,来,减少,扩容,的,数据,迁移,量,我们,最后,选择,的,是,倍数,扩容,也就是,每次,扩容,都,把,库,和,表,的,数量,翻倍,这样,只有,一半,的,数据,需要,迁移,另一半,不,用,动,迁移,量,减少,了,一半,而且,我们,的,分库分表,数量,是,8库32表,都是,2的,倍数,方便,倍数,扩容,以后,扩容,的话,直接,翻倍,成,16库64表,只有,一半,数据,需要,迁移,比较,方便,这个,坑,告诉,我们,设计,分库分表,方案,的,时候,就要,考虑,未来,的,扩容,问题,选择,方便,扩容,的,分片,算法,和,数量,避免,以后,扩容,很,痛苦。

五、经验总结

最后,总结,一下,这次,分库分表,迁移,的,经验,和,教训。

第一,分库分表要慎重,不要为了分而分,分库分表,能,解决,单库单表,的,性能,瓶颈,但是,也,会,带来,很多,复杂度,比如,跨库,查询,分布式,事务,扩容,迁移,运维,复杂度,等等,所以,不,要,盲目,分库分表,只有,当,单库单表,真的,遇到,性能,瓶颈,了,再,考虑,分库分表,如果,单库单表,还,能,扛,住,就,不要,分,能,通过,优化,索引,SQL,缓存,读写,分离,等,方式,解决,的,就,先,用,这些,方式,不要,上来,就,分库分表,不然,会,增加,很多,不必要,的,复杂度。

第二,方案设计要充分考虑未来扩展,设计,分库分表,方案,的,时候,要,充分,考虑,未来,的,数据量,增长,和,扩容,需求,选择,合适,的,分片,维度,算法,和,数量,预留,足够,的,扩展,空间,避免,刚,分,完,很快,又,不够,了,需要,再次,分,很,麻烦,而且,要,选择,方便,扩容,的,方案,比如,倍数,扩容,一致性,哈希,等等,减少,未来,扩容,的,成本。

第三,迁移要做好充分准备和测试,分库分表,迁移,是,很,复杂,的,事情,一定要,做好,充分,的,准备,和,测试,迁移,工具,要,充分,测试,各种,场景,数据,校验,工具,也,要,准备,好,切流,方案,和,回滚,方案,都,要,提前,准备,好,并且,在,测试,环境,充分,演练,确保,没问题,了,再,在,生产,环境,执行,不要,没,准备,好,就,贸然,迁移,很,容易,出,问题,造成,业务,影响。

第四,要灰度切流,密切监控,切流,的,时候,一定,要,灰度,进行,不要,一下子,全,切,先,切,小部分,流量,观察,没问题,再,逐步,增加,而且,要,密切,监控,新库,的,各种,指标,一旦,有,异常,立即,回滚,保证,业务,不,受,影响,不要,图快,一下子,全,切,出,了,问题,影响,很大。

第五,复杂查询要考虑用其他系统配合,分库分表,之后,跨库,查询,和,复杂,统计,查询,会,很,麻烦,性能,也,差,要,考虑,用,其他,系统,配合,比如,Elasticsearch,做,复杂,查询,和,全文,检索,用,OLAP,系统,做,统计,分析,用,Redis,做,缓存,等等,不要,什么,查询,都,走,MySQL,MySQL,只,负责,简单,的,按,分片键,的,查询,和,写入,这样,架构,更,合理,性能,也,更,好。

六、写在最后

数据库,分库分表,迁移,是,一个,很,复杂,也,很,有,挑战,的,项目,涉及,到,方案,设计,工具,开发,数据,迁移,数据,校验,切流,回滚,等,很多,环节,每个,环节,都,不能,出错,不然,可能,造成,数据,丢失,或者,业务,中断,影响,很大,但是,只要,做好,充分,的,准备,和,测试,按部就班,地,执行,还是,能,顺利,完成,的。

我们,这次,迁移,整体,还是,比较,顺利,的,虽然,踩,了,一些,坑,但是,都,及时,解决,了,没有,造成,大,的,业务,影响,迁移,完成,之后,数据库,的,性能,提升,了,很多,查询,和,写入,都,更快,了,扩展性,也,好,了,很多,能,支撑,未来,几年,的,业务,增长,整体,效果,还是,很,不错,的。

希望,这篇,文章,能,给,正在,做,或者,准备,做,分库分表,迁移,的,朋友,一些,参考,和,启发,也,欢迎,大家,在,评论,区,分享,你们,的,分库分表,经验,和,遇到,的,坑,一起,交流,一起,进步。

愿,我们,都,能,在,技术,的,道路,上,不断,学习,不断,成长,解决,各种,技术,难题,做,出,稳定,可靠,高性能,的,系统。