简聊雪花算法Snowflake快乐认知
1. 算法定义与核心思想
Snowflake(雪花算法)是Twitter开源的分布式ID生成算法,用于在分布式系统中生成全局唯一且有序的64位Long型ID。其核心思想是将ID拆分为多个字段,通过组合时间戳、机器标识和序列号确保唯一性与有序性。
2. 算法组成结构
一个典型的64位Snowflake ID结构如下:
| 字段 | 位数 | 说明 |
|---|---|---|
| 符号位 | 1 | 固定为0(ID为正数) |
| 时间戳 | 41 | 毫秒级时间戳(支持约69年) |
| 数据中心ID | 5 | 标识数据中心(支持32个) |
| 机器ID | 5 | 标识同一数据中心下的机器(支持32台) |
| 序列号 | 12 | 同一毫秒内的自增序列(支持每毫秒4096个ID) |
示例:
0 | 1623456789000 | 00001 | 00101 | 000000000111
3、用「快递包裹单号」的例子,解释雪花算法:
想象你开了一家快递公司,每天要处理几百万个包裹。每个包裹都需要一个唯一单号,而且要满足:
-
绝对不重复(不能有两个包裹用同一个单号)
-
能看出时间顺序(单号按时间变大,方便快速整理包裹)
-
多个分店同时生成单号(比如北京店、上海店同时工作)
这时候,你会怎么设计单号?
4、雪花算法的解决方案:
单号 = 时间 + 分店编号 + 当天包裹序号
(就像拼积木一样把三部分拼成一个大数字)
具体例子:
假设今天是 2024年1月1日,你有 3个分店(北京店=1,上海店=2,广州店=3),每个分店每秒最多处理 1000个包裹。
生成单号的规则:
-
时间部分:记录包裹生成的精确到毫秒的时间戳(比如 09:30:25.500 → 转成一串数字)
-
分店编号:每个分店有唯一编号(北京店=1,上海店=2...)
-
包裹序号:同一毫秒内,如果分店要生成多个单号,就按 1,2,3... 顺序编号
5、举个真实单号:
1257894001234567891(实际是64位二进制,这里简化成十进制)
拆解这个单号:
-
前41位(时间):2024年1月1日 09:30:25.500
-
中间10位(分店):北京店(编号1)
-
最后12位(序号):当天这个分店在这个时间点生成的第500个包裹
6、为什么这个方案好用?
-
绝对不重复:不同时间生成的单号肯定不同;同一时间不同分店生成的单号不同;同一时间同一分店用序号区分
-
时间有序:单号整体随时间递增,数据库存包裹时可以直接按顺序堆放,查询更快
-
分布式友好:北京店和上海店不需要互相问"你生成到多少号了",各自独立工作
7、对比UUID的快递单号:
如果使用UUID,单号可能是:550e8400-e29b-41d4-a716-446655440000
-
问题1:完全无序,包裹按单号堆放会东一个西一个,找起来慢
-
问题2:太长了(36个字符),快递员抄写容易出错
-
问题3:无法看出是哪个分店、什么时间生成的
8、现实中的使用场景:
-
电商订单号:
2024010112302512345(前段是时间,后段是分店和序号) -
聊天消息ID:微信消息按时间顺序排列,快速定位到某条消息
-
日志流水号:系统故障时,按日志ID顺序排查问题
一句话总结:
雪花算法就像给每个事件打一个「时间戳+地点+流水号」的三合一标签,让计算机世界里的所有事情都有序排队。
9、【注意】
潜在限制
- 时间回拨问题
若系统时钟回拨(如NTP同步导致时间倒退),可能生成重复ID。需通过记录上次时间戳并阻塞等待来解决。 - ID长度固定
64位长度在某些场景(如需要携带业务信息)可能不足,需结合其他算法(如UUID)或扩展字段。 - 机器ID分配挑战
需合理分配数据中心ID和机器ID,避免冲突。大规模集群需预分配或动态管理ID。
改进方案
- 调整时间戳精度
将时间戳单位从毫秒改为秒,节约10位扩展序列号,支持每秒生成419万个ID。 - 引入机器ID预分配
通过配置中心预分配机器ID,避免手动配置错误。 - 混合时钟策略
检测到时钟回拨时,切换至备用时钟生成ID,确保服务可用性
面基:雪花算法Snowflake时钟回拨问题解决方案-CSDN博客
(望各位潘安、各位子健/各位彦祖、于晏不吝赐教!多多指正!🙏)
更多推荐


所有评论(0)