雪花算法是 Twitter 内部使用的分布式全局唯一 ID 生成算法,并将其开源。本文介绍算法原理、及其一些实际使用中的问题和解法。
算法原理
雪花算法生成的是一个 Long 类型的 ID,Long 占用 64 个 bit 位,该算法将 bit 位分为以下部分:
符号位 | 时间戳 | 机器 id | sequence | |
---|---|---|---|---|
占用 | 1 bit | 41 bit | 10 bit | 12 bit |
符号位:通常为 0,代表正数
时间戳:毫秒数,不是直接从 1970 年开始的时间戳,而是代表可使用时间(当前时间减去开始使用时间),大约可使用 2^41 毫秒约 69 年。
机器 id:高 5 位为数据中心 id,低 5 位为机器 id
sequence:在同一毫秒内从 0 开始的计数器,最大 2^12 为 4096 个,当超过 4096 时,则阻塞等待下一毫秒。既每秒单机可支持并发约为 400 万。
算法实现相对简单,本文就不贴代码了。重点是 需要保障机器 id 唯一,可通过配置、数据库、redis、zk 等实现。
问题与解法
原始的算法在实际使用场景中,可能会碰到以下问题:
时钟回拨
时钟回拨会导致生成重复的 ID,可通过以下方式解决:
- 与最后生成时间做对比
- 回拨时间较短时,可阻塞等待
- 否则,可以重新获取新的机器 id
此方案可能会导致机器 id 消耗太快,可对时间戳、sequence 占用 bit 进行调整。不过不必太过担心,机器 id 也是可以重复使用的,只要不是使用中的重复就好。
前端 JS 精度
JS 内置有 32 位整数,而 number 类型的安全整数是 53 位。如果超过 53 位,则精度会丢失。当碰见雪花算法时,为了正确表示,则只能使用 2^31 毫秒约 24 天。
解决方案:调整时间戳为秒:则能使用 2^31 秒约 68 年。此时,单机并发则为 4096。如果不够,可以适当调小机器 id bit 位数,调大 sequence 位数,使并发增加。
分库分表
分库分表通常采用取模算法,当路由字段使用了雪花算法时,会有什么问题呢?
数据分布不均匀
在同一时间内,sequence 自增永远从 0 开始。当分库分表采用取模算法时,会导致生成的 ID 一直落在前面的库、表里,造成数据倾斜,影响性能。此种现象在单位时间(毫秒、秒)并发低、或分表较多的场景下尤为突出。
解决方案:sequence 从一个随机数开始。
随机范围选择,需要在以下几点取一个平衡:
- 随机范围太大:将会造成 sequence 浪费,并发降低
可通过调大 sequence 占用 bit 解决
- 太小:将会导致后续分库分表扩容后,数据又倾斜了
建议:取一个未来可能的最大分表数。
控制路由目标表
当分库分表数据已经发生倾斜不均匀了,该如何解决呢?
假设共有 4 个实例、分库为 16、分表数为 128,数据倾斜将造成第一个实例数据过多、性能降低。需要将后续数据落在其它实例上既不落在 0-31 表上,以降低第一个实例压力,待数据分布均匀后,再使用前面的算法。
基于 sequence 随机开始,有以下方案:
方案一
将 sequence 随机开始,递增后的值,执行一下路由算法,当其落在其它实例上时,才返回;否则继续递增。
优点:简单 缺点:id 生成器通常为中间件团队的服务,并且后续需要恢复之前的算法,修改麻烦
方案二
我们知道新的 sequence 要求:
- 与老 sequence 一一映射不会重复
- 与老 sequence 一样,单调递增
- 路由后落在指定的表里
为了讲解方便,我们假设分了 8 张表:0-7。需要使新的 sequence 落在 表 3-6 上。假设 x 轴为从 ID 服务器得到原始 sequence,则 y 可能的值分布如图所示:x、y 都从 0 开始
可以找到规律:y 为从0开始,第 x+1 个有效的值。
当路由运算后落在表3-6上,即为有效
在实现时,注意以下几点:
- 正确解析出原始 sequence,并用新 sequence 组装新的 ID
- 新 sequence 的最大值,不能大于其占用 bit 所位能代表的最大值
当超过时,可等待后取下一个时间的 sequence
- 由于新老 sequence 是一一映射,所以可以提前缓存结果,避免 cpu 消耗
以上两种方案都有一个影响:会浪费更多的 sequence,使最大并发降低,使用时请结合实际情况。
总结
本文介绍了雪花算法原理及其在使用过程中可能出现的问题和解法。如果你在使用中有碰到其它问题或者有更好的解法,请评论留言吧!
推荐阅读
招贤纳士
政采云技术团队(Zero),一个富有激情、创造力和执行力的团队,Base 在风景如画的杭州。团队现有300多名研发小伙伴,既有来自阿里、华为、网易的“老”兵,也有来自浙大、中科大、杭电等校的新人。团队在日常业务开发之外,还分别在云原生、区块链、人工智能、低代码平台、中间件、大数据、物料体系、工程平台、性能体验、可视化等领域进行技术探索和实践,推动并落地了一系列的内部技术产品,持续探索技术的新边界。此外,团队还纷纷投身社区建设,目前已经是 google flutter、scikit-learn、Apache Dubbo、Apache Rocketmq、Apache Pulsar、CNCF Dapr、Apache DolphinScheduler、alibaba Seata 等众多优秀开源社区的贡献者。如果你想改变一直被事折腾,希望开始折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊……如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的技术团队的成长过程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 zcy-tc@cai-inc.com
微信公众号
文章同步发布,政采云技术团队公众号,欢迎关注