小猿日记(11) - 单表亿级数据分表实战
概述
5000万单表数据,没有自增ID,要切分到128个表中。
如何选择切分字段,如何优化迁移速度,如何估计分表还是分库分表,如何确定分表数量?
口水记
最近将单表进行了拆分。
虽然是saas平台的权限系统,但是由于前期设计问题,开始在某些表中是没有租户标识的
所以这次给表加上了租户的标识。
改造数据库表结构,最大的难点不是知道如何改。而是变更落地。不遗漏。
经过两次的排查,将所有接口,所有依赖应用全部找出来,全部进行修改。
虽说没有测试人员,但是也顺利上线,没有bug。
然后就是分表问题,这里不选择分库,原因就是,我们的产品面向的是B端,数据库压力并不大,看了现在数据库的一些指标,单个库完全能够支持。
分表数量如何取,这里面要根据实际的一个情况来。
比如说,你目前产品的一个增长量,该数据与什么有关,计算出相关的公式。
按照3年以上(这个时间,按照实际的一个情况选择,更多的情况下,很多数据会有一个瓶颈,也就是到某个程度,不会再增加,我目前的这个数据表就属于这种情况,该数据量与用户有关,市场只有这么大,一定用户量后,数据是不会再怎么增加了,因为用户已经到瓶颈了)的一个时间,单表最大千万级数据量,计算出合适的分表量。
最后就是比较关键的一点,数据的迁移。
开始也想了平滑迁移,但是感觉没有必要,我们的产品在夜晚基本没人使用,完全可以选择那个时间段,进行停机迁移。
既然选择了停机迁移,方案就非常简单了。
一:关闭入口流量 二:数据迁移
三:动态切换
其中数据迁移是最大的时间占比。
由于那张大的单表没有自增id,其实是比较难处理迁移全部数据的,分页查询,我试了一下,5万一页,查询第一页很快,查询最后一页的时候,30秒还无法查询出来,当时把sql停了。
这种方案,实际操作一下sql,就能知道,无法进行。
5000W数据,分页查询,5W一页,分1000次,即使按照平均时间10秒算,需要的时间也是太久。
所以就需要考虑其他的方案了。
根据创建时间/修改时间的区间再分页查询(可行,建立创建时间的索引)
由于ID是UUID转换而成的字符串,所以也可以考虑字符串区间再分页查询(可行,但是实际效果不知)
使用租户标识再分页查询(可行,也是这次迁移选择的方案)
由于租户标识是有单独的表存储,所以完全可以将租户标识全部获取到。
再根据租户标识进行分页查询,单次查询1000。(为什么使用1000,稍后会说到)
为了速度考虑,一定要使用多线程。
这种情况下,可以使用ConcurrentLinkedQueue存储所有的租户标识。
每个线程通过poll操作,获取到一个租户标识后再进行操作。
单次只查询1000数据量,是为了内存考虑,查询过大,很容易就OOM。
而且单次插入数据,也建议在1000条左右。过大可能会造成异常(mysql对语句的长度有限制,默认是 4M)。
这里在批量插入数据的时候,遇到了一个ShardingJDBC不支持批量插入的情况,这是由于老版本不支持这功能引起的,解决方案在这里已经说明: https://chenhx.blog.****.net/article/details/106408162
通过租户id,多线程查询的方式,顺利把5000W条数据的迁移控制在了30分钟左右。
算是一个比较成功的案例。
小结
性能、速度过慢时,多思考一下其他的方式
多线程比单线程跑,不只是快了一点点,但是注意,起多少线程比较合适,需要根据自己的服务器配置,数据库压力来选择
不正经语录
项目改造,别怂,就是干
背锅,别方,用力甩出去
声明
本文故事纯属遐想,如有雷同,我是原创。
欢迎转载。
转载请务必注明以下信息。
原作者:谙忆
原文链接: https://chenhx.blog.****.net/article/details/106446270
公众号
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;
欢迎扫码关注公众号:程序编程之旅