TL;DR(30 秒扫完)
- 主流方案五种:UUID / DB 自增 / Redis INCR / 雪花算法 / Leaf 号段
- Leaf 三大模式:Leaf-Segment(号段+双 Buffer,可读)/ Leaf-Snowflake(雪花+位运算,快)/ Leaf-Snowflake+ZK(自动分配 workerId)
- 64 位构成:1 符号 + 41 时间戳(69 年)+ 10 workerId(1024 台机器)+ 12 序列(4096/ms)
- 时钟回拨四方案:Leaf 严格抛异常 / 等待回拨时长 / 上一机器时间戳 / TSC 时间戳绕过
- 选型口诀:业务可读→号段;高 QPS 内部→雪花;自动分配 workerId→雪花+ZK
关键结论
结论 ALeaf 号段模式核心是"双 Buffer"——前台在用 + 后台异步预加载,避免号段耗尽瞬间阻塞
结论 B雪花算法 64 位构成清晰,最大坑是时钟回拨导致 ID 重复
结论 CLeaf 采用严格抛异常 + 报警处理时钟回拨,金融级场景不能容忍重复 ID
结论 D选型核心是"业务可读性 vs 性能 vs 依赖成本"
完整讲解(费曼四步)
STEP 1 · 概念
分布式 ID 生成:在分布式环境下生成全局唯一、有序(或局部有序)、高性能的 ID 的机制。STEP 2 · 大白话
类比身份证发放:- UUID:全国随机发,无序不可读
- DB 自增:只有一家发证处(单点瓶颈)
- Redis INCR:所有证从 Redis 领号(依赖 Redis 可用性)
- 雪花算法:1000 家发证处,每家用时间戳+机器号+序列号组合,最快但有回拨风险
- Leaf 号段:发证处提前领一批号段(1000 个),用完再领,降低请求频率
STEP 3 · 底层
3.1 主流分布式 ID 方案完整对比
| 方案 | 依赖 | 单调性 | 时钟风险 | 性能 | 典型场景 |
|---|---|---|---|---|---|
| UUID | 无 | 无 | 无 | 高 | 无强要求 |
| DB 自增 | DB | 严格 | 无 | 低 | 单库低并发 |
| Redis INCR | Redis | 严格 | 无 | 高 | 高 QPS 简单场景 |
| 雪花算法 | 时钟 | 严格 | 回拨 | 极高 | 高 QPS 内部 ID |
| Leaf 号段 | DB | 局部 | 无 | 高 | 业务可读(订单号) |
| Leaf-Snowflake + ZK | ZK | 严格 | 回拨 | 极高 | 需要自动分配 workerId |
3.2 Leaf-Segment 号段模式(详解)
核心思想:从 DB 一次取一批号段(step=1000)在本地缓存,用完再取,降低 DB 访问频率到 1/1000。 DB 表结构:CREATE TABLE leaf_alloc (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64) UNIQUE, -- 号段名称(如"订单号")
max_id BIGINT, -- 当前已分配的最大 ID
step INT -- 每次分配步长
);
号段获取 SQL:
UPDATE leaf_alloc
SET max_id = max_id + step
WHERE name = 'order_id';
返回 max_id - step + 1 到 max_id 的号段。
双 Buffer 机制:- 一个 buffer 在前台使用、另一个在后台异步预加载下一批
- 前台 buffer 使用到阈值(如 10%)时触发后台预加载
- 避免号段耗尽瞬间阻塞业务(关键设计)
- 依赖 DB、局部单调(号段连续)、号段连续可读、性能高(本地生成)
- 适合订单号、业务可读场景
3.3 Leaf-Snowflake 雪花算法(详解)
64 位位运算构成:+------+----------------------+----------+-----------+
| 符号 | 时间戳(41位) | workerId | 序列号(12) |
| 1 位 | 69 年(约) | 10 位 | 4096/ms |
+------+----------------------+----------+-----------+
- 1 位符号:始终为 0(Long 正数)
- 41 位时间戳:从起始时间开始计,约 69 年
- 10 位机器 ID:最多 1024 台机器(可通过 ZooKeeper/Curator 分配 workerId)
- 12 位序列号:每毫秒 4096 个 ID
- 单机生成、无网络调用、QPS 百万级
- 最大坑:时钟回拨(时间倒退导致 ID 重复)
3.4 时钟回拨四种解决方案
| 方案 | 说明 | Leaf 采用? |
|---|---|---|
| 严格抛异常 | 检测到回拨直接抛异常并报警,人工介入 | ✅ 金融级场景首选 |
| 等待回拨时长 | 等回拨过去再发号 | 宽松场景 |
| 上一机器时间戳 | 用上次记录的最大时间戳 | 有兼容问题 |
| TSC 时间戳计数器 | 用 CPU 时间戳计数器绕过系统时钟 | 硬件依赖 |
if (currentTime < lastTime) {
// 时钟回拨
throw new RuntimeException("Clock moved backwards");
}
3.5 Leaf 三大模式选型
| 模式 | 依赖 | 单调性 | 时钟风险 | 场景 |
|---|---|---|---|---|
| Leaf-Segment | DB | 局部单调 | 无 | 订单号、业务可读 |
| Leaf-Snowflake | 时钟 | 严格单调 | 有回拨 | 高 QPS 内部 ID |
| Leaf-Snowflake + ZK | ZK | 严格单调 | 有回拨 | 需自动分配 workerId |
3.6 为什么美团选 Leaf-Segment 做订单号?
- 业务可读性:订单号业务方好理解(连续增长)
- 局部有序:分库分表 hash 后接近有序,避免索引碎片
- 避免时钟回拨风险:金融级场景不能容忍 ID 重复
- 雪花每秒 4096 个太快:订单量对不上
STEP 4 · 简化(口诀)
五种方案:UUID 随机 / DB 单点 / Redis 依赖 / 雪花回拨 / Leaf 号段可读>
Leaf 双 Buffer:前台在用 + 后台预加载(10% 阈值触发)>
雪花 64 位:1 符号 + 41 时间戳(69 年)+ 10 workerId(1024 台)+ 12 序列(4096/ms)>
时钟回拨四方案:Leaf 严格抛异常 / 等待回拨时长 / 上一机器时间戳 / TSC 绕过>
选型口诀:业务可读→号段;高 QPS 内部→雪花;自动分配 workerId→雪花+ZK
延伸追问
号段模式的双 Buffer 机制具体怎么工作?为什么不直接同步预加载?
要点:前台 buffer 使用到阈值(如 10%)时触发后台异步加载下一个号段;同步加载会在号段耗尽瞬间阻塞业务,双 Buffer 保证前台永远有号段可用
雪花算法时钟回拨如何检测和解决?
要点:检测
currentTime < lastTime 判定回拨;Leaf 严格模式抛异常报警;宽松模式等待回拨时长;使用 TSC(时间戳计数器)绕过系统时钟;使用上一台机器的时间戳(有兼容问题)为什么美团选择 Leaf-Segment 做订单号,而不是雪花算法?
要点:订单号需要局部有序(分库分表 hash 后接近有序)、可读性(业务方好理解)、避免时钟回拨风险(金融场景不能容忍 ID 重复);雪花算法每毫秒 4096 个 ID 太快,订单量对不上
workerId 冲突怎么处理?
要点:手动分配容易冲突,ZK/Curator 自动分配避免冲突;每台机器启动时申请 workerId、进程崩溃释放;ZK 临时节点保证唯一性
速查表
五种方案 · UUID 随机 · DB 单点 · Redis 依赖 · 雪花回拨 · Leaf 号段可读
Leaf 双 Buffer · 前台在用 + 后台异步预加载(10% 阈值触发)
雪花 64 位 · 1 符号 + 41 时间戳(69 年)+ 10 workerId(1024 台)+ 12 序列(4096/ms)
时钟回拨 · Leaf 严格抛异常(金融首选)/ 等待 / 上一机器 / TSC
Leaf 三模式 · Segment(DB+号段)· Snowflake(时钟+位运算)· Snowflake+ZK(自动 workerId)
选型口诀 · 业务可读→号段 · 高 QPS 内部→雪花 · 自动分配→雪花+ZK
Anki 候选卡片
Q: 主流分布式 ID 方案有哪几种?
A: UUID / DB 自增 / Redis INCR / 雪花算法 / Leaf 号段 / Leaf-Snowflake+ZK
Q: Leaf 号段双 Buffer 机制?
A: 前台 buffer 使用到阈值(10%)时触发后台异步预加载下一批,避免号段耗尽瞬间阻塞业务
Q: Leaf 号段模式的 DB 表结构?
A: leaf_alloc(id, name, max_id, step),UPDATE max_id = max_id + step 原子获取号段
Q: 雪花算法 64 位位运算构成?
A: 1 符号 + 41 时间戳(69 年)+ 10 workerId(1024 台)+ 12 序列号(4096/ms)
Q: 时钟回拨四种解决方案?
A: Leaf 严格抛异常报警(金融首选)/ 等待回拨时长 / 上一机器时间戳 / TSC 时间戳绕过
Q: Leaf 三大模式选型?
A: Leaf-Segment(DB+号段,业务可读)/ Leaf-Snowflake(时钟+位运算,高 QPS 内部)/ Leaf-Snowflake+ZK(自动 workerId)
Q: workerId 冲突怎么处理?
A: 手动分配容易冲突,ZK/Curator 自动分配,临时节点保证唯一性
Q: 为什么美团用 Leaf-Segment 做订单号而不是雪花?
A: 业务可读性 + 局部有序(分库分表 hash 后接近有序)+ 避免时钟回拨风险 + 雪花每秒 4096 太快
Q: Leaf 号段模式的性能优势?
A: DB 访问频率降到 1/1000,本地生成 ID 性能高
Q: 为什么金融级场景不用雪花算法?
A: 时钟回拨可能导致 ID 重复,金融级场景不能容忍重复 ID;Leaf 号段无时钟回拨风险
关联题目
- [ ] 《Leaf 生成分布式 ID 的原理?》—— 2026-10-08 Round 1 Q6, 评分 ⭐⭐⭐
- [ ] 《分布式 ID 生成方案都有哪些?》—— 待考
- [ ] 《详细介绍下号段模式生成分布式 ID 的原理和优缺点?》—— 待考
- [ ] 《雪花算法时钟回拨如何检测和处理?》—— 待考
关联知识
Leaf 号段双 Buffer 降低 DB 访问 1/1000;雪花 64 位 1+41+10+12;时钟回拨四方案 Leaf 严格抛异常
身份证发放:DB 单点发证处 / Redis 集中领号 / 雪花 1000 家发证处(时间+机器号+序列)/ Leaf 号段提前领一批
✦ 记 忆 口 诀 ✦
业务可读→号段 / 高 QPS 内部→雪花 / 自动分配→雪花+ZK
关键可视化
暂无可视化
知识关系
⬆️ 前置(Prerequisite)
暂无⚡ 对比(Contrast)
暂无
🎯 概念
📏 规则
⚠️ 误区
🔍 追问
✨ 口诀
共 0 张卡,点击翻面