连载中 5/16

雪花算法:64 位里的精密钟表

2026-06-07 · 3447 阅读 · 0 评论 · 0 赞

号段模式的天花板

双 buffer 让号段模式稳了下来,老王却盯上了新的压力源:公司要做 IoT 设备埋点,每秒百万级事件要打 ID;发号服务再稳,也是所有业务的汇聚点——只要发号动作还要走到某个中心节点,中心就是天花板。Twitter 十几年前遇到了同样的问题,给出的答案是雪花算法(Snowflake):不依赖任何中心,每个节点自己发号。

64 位的三段式拆解

一个 long 型 64 位,被切成四段:

0 | 000110... (41 bit 毫秒时间戳)| 0000000001 (10 bit 机器号)| 000000000001 (12 bit 序列号)
符号位恒 0 保证正数,真正干活的是后三段

1 bit 符号位:恒为 0,保证生成的 ID 是正数,Java 的 long 无符号判断不踩坑。

41 bit 时间戳:存「当前毫秒减去起算纪元」的偏移量。2 的 41 次方毫秒约 69 年——选好起算时间(比如项目上线日),够用到退休。时间戳在最高位,意味着 ID 整体随时间单调递增,InnoDB 顺序写入的梦想实现了。

10 bit 机器号:2 的 10 次方 1024 个节点。每个节点持有一个全局不重复的编号,同一毫秒里不同节点生成的 ID 天然错开——机器号就是分布式下的「身份证」,它的分配问题单独留到第 8 篇。

12 bit 序列号:同一毫秒、同一节点内区分不同 ID 用,2 的 12 次方 4096 个。单机单毫秒发满 4096 个后,怎么办?自旋等待到下一毫秒重新计数。算总账:每毫秒 4096 个乘以 1000 毫秒,单机理论上限约每秒 409 万——实测百万级轻轻松松,百万埋点需求直接击穿。

生成流程:一次自旋的故事

核心逻辑十几行伪代码就能说清:

synchronized long nextId() {
  long now = System.currentTimeMillis();
  if (now 为上一毫秒) {
    seq = (seq + 1) 与上 4095;   // 12 bit 内自增
    if (seq 归零) {              // 本毫秒额度用尽
      now = 等待下一毫秒();      // 自旋,不忙等死循环
    }
  } else {
    seq = 0;                     // 新毫秒从头计数
  }
  lastTimestamp = now;
  return (now - 纪元) 左移 22 | 机器号 左移 12 | seq;
}

三维唯一性一目了然:不同时间(41 bit)、不同机器(10 bit)、不同序列(12 bit),任意一维不同,ID 就不同——世界没有两片相同的雪花,分布式里没有两个相同的 ID。位运算拼装零锁竞争(方法级同步只锁本节点),纳秒级完成。

位数不是圣旨

41、10、12 是 Twitter 按自己场景切的,不是标准。位数是道分配题:时间给得多,可用年头长;机器给得多,横向扩展强;序列给得多,单机峰值高。实际落地时按业务重新分配很常见——机器只有几十台却要发三十年,就可以从机器号里匀几位给时间戳;反过来集群上万台,就从时间里匀给机器号。分配定终身,上线前想清楚,改位数的代价等于换号段(老 ID 还要兼容)。

两个隐藏前提

雪花把发号变成了本机时钟的操作,代价是两个强前提:第一,机器时钟必须可信——时间戳来自系统时钟,时钟回拨会让它发出「过去」的号,这是整个算法的死穴,第 6 篇专题;第二,机器号必须全局唯一——两台机器拿到同一个机器号,同一毫秒就可能发出相同 ID,唯一性瞬间崩塌,第 8 篇专题。

小结

雪花算法一句话:用 64 位的空间换来了时间、机器、序列三维唯一,本地发号吞吐封顶、趋势递增养索引。它把「中心发号」变成「人人发号」,也把风险从「中心挂了」变成「时钟飘了、机器号重了」。下一篇,正面刚它的死穴:时钟回拨到底怎么发生,又有多致命。

503

10 年全栈工程师 · 503咖啡馆主理人

#分布式ID#雪花算法#Snowflake#时间戳#位运算

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞