如何设计网站后台,山西省建设厅投诉网站,技术支持 张家港网站建设,wordpress国内访问问题引入
最近一个业务系统中#xff0c;因为数据量很大#xff0c;经过技术选型#xff0c;综合权衡选择了sharding-Jdbc#xff0c;本文主要讨论的是分库分表的表达式
我们有一个批次总表A#xff0c;还有一个明细表B#xff0c;我们需要对明细表B进行水平拆分#…问题引入
最近一个业务系统中因为数据量很大经过技术选型综合权衡选择了sharding-Jdbc本文主要讨论的是分库分表的表达式
我们有一个批次总表A还有一个明细表B我们需要对明细表B进行水平拆分考虑系统数据的可扩展性和mysql的负载我们打算针对B表进行分表分4个数据库每个数据库64张表使用A表的主键批次id【fnQpid】来作为分片键。
问题演进
第一版本
一开始选用了一个最简单的hash路由策略如下
分库策略为
fnQpid % 4
分表策略为
fnQpid % 64
乍一看没啥问题仔细琢磨后发现了一个问题这样分会导致数据分布不均衡为啥会导致数据不均衡呢
假设某一个fnQpid的数据分在了0库的1分表那么这个fnQpid需要满足什么条件呢
第一分在了0库需要满足fnQpid4m 【m为整数】 》可以推测出fnQpid为偶数
第二分在1分表需要满足fnQpid64n1 【n为整数】》可以推测出fnQpid为奇数
毫无疑问这样的fnQpid是不存在的也就是某一个fnQpid的数据分在了0库的1分表这个假设不成立也就是这样分库分表会导致数据分布不均衡。
第二版本
发现上面的问题后优化了一版分库分表的算法
分库策略
(fnQpid % 256)/64
分表策略
(fnQpid % 256) % 64
简单介绍一下这个方案的思路
先计算总的逻辑表的数量也就是4*64256然后计算fnQpid % 256的值这个值的范围是[0,255]把这256个数据当成是一个整体来看计算其所在的数据库(fnQpid % 256)/64该值的范围是[0,3]最后计算所在分表(fnQpid % 256) % 64该值的数据范围是[0,63]
按照这样的分库分表方式不会出现第一种情况有些表永远不会有数据出现但是这样的路由策略有一个美中不足如图 当批次号连续自增的时候明细表的数据分布是这样的前256个批次的数据在0库接着在1库接着在2库最后在3库再接着又回到0库如此循环往复。
若每个批次有1000条数据那么在短时间内就会有256000的数据落在同一个数据库这个瞬时数据的写入、查询都是一个不小的压力。可以说这个方案数据物理上是分布均衡的但是在短时间内mysql单个数据库的负载是不均衡的。
第三版本
考虑到上面两种问题后继续优化
分库策略为
fnQpid % 4
分表策略为
(fnQpid 2) % 64
简单介绍下这个方案 这个方案是在方案一的基础上进行了分表策略的优化。 一开始是直接用fnQpid % 64这样有问题是fnQpid的最后两位二进制已经参与了数据库fnQpid % 4的计算了再参与分表的计算就会互相影响。新的方案是先踢掉最后两位二进制(fnQpid 2)再参与分表计算数据流入如下图 可以看到数据是按照顺序从0库到3库先填充满所有的0表接着填充满所有的1表…,填充所有的63表再填充满所有的0表如此循环往复。当瞬时间有大量数据写入的时候数据是分散在不同的数据库的因此解决了方案二数据库负载不均衡的问题了
问题总结
为什么分表的数量是64呢为什么不是100呢
针对这个问题大家可以思考下为什么HashMap的初始容量要设置成162的4次幂,redisCluser的哈希槽为什么是163842的14次幂
我个人认为是为了提升速度。因为无论是HashMap还是redisCluser都需要频繁的根据key来计算数组的index这个操作是hash(key)%16、hash(key)%16384这样做就差点意思。
看过hashMap源码的同学都知道源代码上使用了hash(key)15 来计算index也就是hash(key)15等价于hash(key)%16延展下
若n为2的整数次幂时 m % n 等价于 m (n-1)
因此我们的分库分表为了提速分表数量选择了2的整数次幂。最终的分库分表的表达式是这样 分库策略为
fnQpid 3
分表策略为
(fnQpid 2) 63
针对分库分表的策略大家还遇到过什么坑吗欢迎评论区留言