题目:什么是雪花算法,怎么保证不重复的?
难度:low
标签:arch/distributed/id, distributed/snowflake, difficulty/low
评分:⭐⭐⭐⭐☆(4/5)
首先,雪花算法是一个用于生成分布式 ID 的,用于本地生成分布式 ID 的算法。它的核心是通过分段的方式,使用多段,一整个数据的多个数位来生成单调递增的,或者说区域递增的 ID 的一个方式,一个算法。其中有一部分数位是时间戳,用来保证 ID 的自增性。然后通过机器码来保证不同机器生成不同的 ID。通过最后的一部分随机的数位,来保证当前机器上,同一时间产生的,同一时间戳下产生的 ID 不同。
但是它本身也存在一定问题,比如多个机器上出现时间不统一,虽然不会产生相同的 ID,但可能会产生 ID 倒序的生产,因为它是靠时间戳来生成数据的。另外,如果出现时钟回拨,可能同一个机器上会产生同样的 ID,分布式 ID。但是好处上,它是一个在单机上不需要一个中心的支持的 ID,分布式 ID 生成算法,它可以比较快速的生成分布式 ID。要解决刚刚时钟的问题,可以通过记录最后一个 ID。每一个机器的最后一个 ID 进行缓存,在生成时进行比对,来确保生成的 ID 的正确性和不重复性。
优点:
不足:
补充:
0 | 41 位毫秒时间戳 | 10 位机器 ID | 12 位序列号,41 位可支持约 69 年核心考点定位:考察雪花算法的位结构、去重机制、以及工程落地时的关键风险点。
知识点拆解:
1 符号位 + 41 时间戳 + 10 workerId + 12 sequence。41 位毫秒时间戳以 Twitter 2010-11-04 为纪元,可表示 69.7 年递进:位结构 → 去重原理 → 性能 → 三大风险 → 工程兜底
考察方向:
延伸递进面试题:
面试官您好,雪花算法是 Twitter 提出的一种本地生成、无中心节点的分布式 ID 算法,核心是用一个 64 位 long 按位分段。标准分配是:最高 1 位保留符号位为 0,接下来 41 位是毫秒级时间戳(以 2010-11-04 为纪元,可表示约 69 年),接下来 10 位是机器 workerId(最多 1024 台机器),最后 12 位是同一毫秒内的自增序列号(4096/ms,即单机 409.6 万 ID/s 上限)。
不重复的保证分两层:跨机器靠 workerId 位段区分,两台机器生成的 ID 在这 10 位上必不相等;同机器同毫秒靠 sequence 位段区分,每秒内最多 4096 个不同序列值。两个 ID 只要任一段不同,全 ID 就不同。
雪花算法的三大工程风险:第一是 workerId 冲突,如果两台机器拿到相同 workerId,去重机制就崩了,所以工程上必须先解决 workerId 分配问题,常见做法是配置文件、ZK 抢锁、或者从 K8s pod 序号取;第二是时钟不同步,跨机器的 ID 会非严格递增,但不重复;第三是时钟回拨,本地 NTP 同步后时钟往前退,可能生成已用过的 ID。
处理时钟回拨业界通常分三档:小回拨(比如小于 5ms)沿用 lastTimestamp 让 sequence 继续递增;中等回拨 sleep 到正确时间再发;超过阈值直接抛异常阻断。核心思路是宁可暂时不发 ID,也不能发重复 ID。
雪花算法的优点是本地生成无网络调用、QPS 极高,且 ID 大致随时间递增,对 MySQL B+ 树索引非常友好,插入几乎总是追加到叶子页右侧。缺点是强依赖机器时钟,且需要维护 workerId 分配。相比 UUID 更适合业务主键场景,相比数据库自增和号段方案更适合对延迟敏感的业务。