之前给大家介绍过单表超大的时候,需要分表,一般都是用主键进行hash,或者直接用雪花算法生成全局唯一id,然后按2^n 取模,把一张超多数据的表,分成2^n个表。这个时候,问题来了:
如果一个业务里有多个key,例如订单中心,有buyer_id、order_id、seller_id等,我们希望相关的业务都入到同一个库或者同一个表,这样能减少跨库、跨表操作,增加效率。这该怎么办呢?
普通方案
大数据工程师拍了拍脑袋说:这个简单啊,分库前,先用业务id关联一下分库的那个id,然后就知道在哪个库里了,然后再分出去就好了。
然后这个方案就因为系统资源开销太大,访问效率极低, 被领导骂了一通,失败!
优化思路
分库/表策略还得关联表,那肯定是不行的,那怎么做才能直接定位到我们期望的库/表呢?绝对不能等分的时候才去找,那样太慢了。能不能在之前就先定好呢?就像给公寓每个人分配一个大门钥匙那样,有钥匙的就能进公寓,这就不会错了。
如果我们对一个10进制的数字按10取模,取模的结果与这串数的前面所有位都没有任何关系,最后1位决定取模结果:
同理,按100取模,最后2位决定取模结果,按1000取模,最后3位决定取模结果:
同理:一个二进制的值,按2^n取模,也是最后n位决定取模结果:
所以能不能把全局唯一用户id的最后几位作为公寓 钥匙一样,其他id生成的时候带上这把钥匙,就能把一个用户的所有数据都放到同一个公寓(库/表)中呢?理论是可以的!
NX方案出炉
我们在雪花算法的图下加入了订单id生成的示意图, 假定需要分16张表,则需要截取二进制订单id的最后LOG(16,2)=4位,作为分库/分表基因。
然后对订单id用hash生成60位,加上从用户id那边获取的4位基因,形成最终的订单id。其他业务id也使用相同的办法处理。
分库/分表策略时,直接设定使用该id进行水平切分。由于所有业务都有相同的最后4位,这样sharding时都会进入相同的库/表。简直太完美了!
总结
雪花算法是超大数据量下,OLTP事务数据处理环境中用的ID分配方法。其原理是利用决定分库分表的其实是Hash值最后N位(比如4位)。所以我们可以在分库分表策略中使用雪花算法,把相同内容的数据分配到同一台服务器/分区中,这样在使用数据时降低跨库跨分区的Join,极大提升效率。