高 进阶
自增ID与分布式ID#
一句话答案#
单库用自增 ID 简单高效,分布式场景用雪花算法(有序高性能)或号段模式(高可用),UUID 无序不利于索引。
核心要点
| 方案 | 优点 | 缺点 |
|---|---|---|
| UUID | 简单无依赖 | 无序/字符串长/不利索引 |
| 雪花算法 | 有序/高性能 | 时钟回拨问题 |
| 号段模式 | 高可用/可预分配 | 依赖DB |
| Redis自增 | 简单有序 | 依赖Redis |
面试回答(2分钟版)
单库场景下自增 ID 简单高效,天然有序对 B+ 树插入友好,但在分布式场景存在两个问题:不同库的自增 ID 会冲突,而且会暴露业务量。所以分库分表后需要分布式 ID 方案。主流方案有三种:第一是雪花算法,用时间戳+机器ID+序列号组合出全局唯一 ID,有序且性能极高,但要注意时钟回拨可能导致重复,通常通过等待或拒绝服务来规避;第二是号段模式,应用从数据库批量预领一段 ID 回本地分配,高可用且对外部依赖小,美团 Leaf 就是这个思路;第三是 UUID,完全无依赖但无序导致索引页分裂,不适合做主键。我们项目用的是雪花算法的变种,加了机器 ID 自动注册和时钟回拨检测。
追问与易错
追问方向:
- “雪花算法时钟回拨怎么处理?”→ 常见方案:小幅回拨(几毫秒)等待追上后继续;大幅回拨直接报错拒绝生成 ID;也可引入机器启动时间戳校验或使用 Leaf-Snowflake 的 ZooKeeper 方案检测回拨
- “UUID 做主键有什么问题?”→ UUID 无序导致 B+ 树随机插入频繁页分裂,写入性能差;字符串类型占 36 字节远大于 bigint 的 8 字节,索引空间膨胀;二级索引叶子存主键值,主键越大二级索引越臃肿
- “号段模式怎么实现?”→ 数据库维护一张号段表(biz_tag + max_id + step),应用启动时批量获取一段 ID(如 1~1000)缓存在本地;用完后再申请下一段;美团 Leaf 采用双 Buffer 预加载避免切段时的抖动
易错点:
- ❌ 自增 ID 没有问题——暴露业务量/分库不唯一
- ❌ 雪花算法不会重复——时钟回拨时可能重复