在分布式系统中,生成全局唯一、有序且高性能的 ID 是核心需求。以下是几种主流方案的对比与选型建议。
1. 雪花算法 (Snowflake)
Twitter 开源的经典方案,生成 64 位 Long 型 ID。
结构
- 1 bit: 符号位 (始终为 0)。
- 41 bits: 时间戳 (毫秒级,可用约 69 年)。
- 10 bits: 机器 ID (5 位数据中心 ID + 5 位工作机器 ID)。
- 12 bits: 序列号 (毫秒内自增,支持每毫秒 4096 个 ID)。
优缺点
- 优点:
- 高性能: 本地生成,无网络开销,TPS 极高。
- 有序性: 趋势递增,对数据库 B+ 树索引友好。
- 不依赖 DB: 避免了单点故障。
- 缺点:
- 强依赖时钟: 若机器时钟回拨,可能导致 ID 重复 (需通过等待或抛异常处理)。
2. 数据库号段模式 (Segment)
美团 Leaf、滴滴 TinyID 等中间件的核心机制。
原理
不每次请求数据库,而是从数据库领一个“号段” (如 1000-2000) 加载到内存,用完后再领下一个。
优缺点
- 优点:
- 高可用: 数据库宕机短时间内不影响服务 (内存中有缓存号段)。
- 高性能: 大幅减少数据库 IO。
- 缺点:
- ID 不随机: 可能暴露业务量 (如订单号连续)。
3. Redis 生成 (INCR)
利用 Redis 的原子性操作 INCR 或 INCRBY。
优缺点
- 优点: 实现简单,性能优于数据库,天然有序。
- 缺点:
- 运维成本: 需维护 Redis 高可用集群。
- 持久化风险: RDB/AOF 可能存在数据丢失或重复风险。
4. UUID
优缺点
- 优点: 本地生成,代码简单,全球唯一。
- 缺点:
- 无序: 导致 B+ 树索引频繁分裂,写入性能差 (主键大忌)。
- 存储大: 36 字符 (String),占用空间大。
- 无业务含义。
5. 数据库自增 ID (Flicker 方案)
利用 MySQL 的 replace into 或 auto_increment,通过设置不同 起始值 和 步长 支持多主架构。
- 示例: 机器 A (1, 3, 5…), 机器 B (2, 4, 6…)。
- 缺点: 扩展困难 (加机器需调整步长),数据库仍是瓶颈。
总结建议
| 场景 | 推荐方案 |
|---|---|
| 一般业务 | Snowflake (或百度 UidGenerator) |
| 对连续性/安全性有要求 | 号段模式 (如美团 Leaf-segment) |
| 主键生成 | 避免使用 UUID |