数据库自增长序列或字段

UUID

使用 UUID to Int64 的方法

Redis 生成 ID

Twitter 的 snowflake 算法

利用 zookeeper 生成唯一 ID

MongoDB 的 ObjectId

七种方案只有名字没有取舍,等于没答。分布式主键的评价维度是固定的五维:唯一性、趋势递增(对索引友好)、有序性含义、可用性/性能(生成器依赖)、信息安全性(是否可猜测)。本文按五维给七方案打分,并给出场景化选型结论。

五维评价框架

  • 唯一性:全局不重复(底线)
  • 趋势递增:B+Tree 聚簇索引友好(尾插无页分裂)
  • 生成依赖:是否需要中心组件(DB/Redis/ZK),依赖即单点与延迟来源
  • 吞吐与延迟:本地生成(ns 级)vs 远程生成(ms 级/批量号段摊销)
  • 安全性:是否暴露业务量/时间(可枚举猜测)

七方案逐一评析

1. 数据库自增(单库):递增完美、唯一性靠单库;但分库分表后冲突,且暴露业务量、生成依赖 DB 写。单库时代的最优解,分布式的起点问题。

2. 多库自增(步长法):库 1 发 1,3,5…、库 2 发 2,4,6…(auto_increment_offset+step);扩容改步长痛苦、仍依赖 DB。过渡方案。

3. UUID:本地生成、无依赖、唯一性概率足够;但无序导致聚簇索引页分裂+随机 IO、36 字符存储大、不可读。适合:非主键场景(消息 ID、文件名)、或存储为 16 字节二进制且接受索引代价。

4. UUID to Int64 / 改造 UUID:截取/哈希压缩为 long:解决长度但引入碰撞风险与仍无序问题;雪花出现前的过渡思路,今天无选用理由。

5. Redis 生成(INCR / 号段):INCR 原子自增全局唯一、递增友好;依赖 Redis(需持久化+主从防丢号)。号段模式(Leaf-segment):一次取一批(如 1000 个)本地发完再取,Redis 压力降为 1/1000,双 buffer 预加载消除取号延迟——美团 Leaf 的核心。

6. Snowflake(雪花):64 bit = 1 符号 + 41 时间戳(ms) + 10 机器位 + 12 序列位;本地生成、趋势递增、含时间可排序。要害在时钟回拨(回拨期间可能重号):应对=拒绝生成/等待/借用未来时间(各实现策略不同);机器位分配需规划(ZK/配置中心下发)。生态实现:Hutool、Leaf-snowflake、Sonyflake(Go,时钟回拨更保守)。

7. ZooKeeper 序列节点:持久顺序节点 znode 序号全局唯一;强一致但每次生成一次 ZK 写,吞吐与延迟最差;适合低频高可靠场景(订单号备选),或作为雪花机器位分配器而非 ID 生成器本体。

8. MongoDB ObjectId(补充):12 字节=时间戳+机器+PID+计数器,本地生成趋势递增;与 Mongo 生态绑定,关系库中可用但语义冗余。

选型决策表

场景 推荐 理由
单库/未分片 DB 自增 简单、索引最优
分库分表 + 有高可用号段服务 号段模式(Leaf-segment) 递增、去中心依赖弱(DB 号段表)、吞吐高
分库分表 + 去 DB 依赖 Snowflake 本地生成、递增、含时间序
只需唯一不需有序(消息/文件 ID) UUID(二进制存储) 零依赖
低频、强一致要求 ZK 序列 CP 保证
Mongo 生态 ObjectId 原生

工程细节清单

  • 雪花机器位:容器化环境 IP/主机名不稳定,用注册中心临时分配或配置中心静态映射,防 IP 复用重号
  • 时钟回拨监控:NTP 跳变告警 + 生成器回拨保护策略演练
  • ID 语义分离:主键 ID 与业务单号分离——主键用雪花/号段(技术序),业务单号(订单号)另编(含日期/业务码/校验位,面向人与客服)
  • 前端精度:JS Number 超 2^53 丢精度,雪花 ID 出接口转字符串
  • 压测验证:生成器吞吐(雪花单机理论 409.6 万/ms 序列位上限,实际受时钟与锁限制)与号段步长调优

分布式主键选型 = 五维打分 + 场景匹配:要索引友好选递增系(号段/雪花),要零依赖选 UUID 系,要强一致选 ZK 系;再补上时钟回拨、机器位、精度三个工程细节,方案才从”名字”变成”可上线的设计”。