在分布式系统中,生成全局唯一ID是核心需求之一,尤其在微服务、分库分表等场景下。以下是几种主流分布式ID生成方案的原理、优缺点及适用场景的详细分析:
1. UUID
- 原理:基于时间、节点信息、随机数生成128位唯一标识符(如
550e8400-e29b-41d4-a716-446655440000)。 - 优点:
- 完全分布式,无需中心节点。
- 生成速度快,无网络开销。
- 缺点:
- 无序性导致数据库插入性能低(B+树分裂)。
- 存储空间大(36字符),可读性差。
- 适用场景:日志跟踪、临时标识等无需有序性的场景。
2. 数据库自增ID
- 原理:利用数据库自增主键(
AUTO_INCREMENT)生成唯一ID。 - 扩展方案:
- 分库分表:设置不同起始值和步长(如DB1:1,4,7…,DB2:2,5,8…)。
- 优点:
- 绝对有序,适合范围查询。
- 实现简单,无需额外组件。
- 缺点:
- 扩展性差,新增节点需重新规划步长。
- 数据库压力大,存在性能瓶颈。
- 适用场景:小规模系统,ID需求稳定且无需频繁扩容。
3. Redis生成ID
- 原理:利用Redis的
INCR或INCRBY命令生成递增ID。 - 优化方案:
- 批量预取:一次获取ID段(如1~1000)缓存在本地。
- 优点:
- 性能高(10万+/秒),优于数据库。
- 支持分布式环境。
- 缺点:
- 需处理Redis持久化问题(宕机可能导致ID重复)。
- 集群模式下需协调多节点ID分配。
- 适用场景:高并发但允许短暂ID不连续的场景(如秒杀订单)。
4. Snowflake算法
- 原理:64位ID = 时间戳(41bit) + 机器ID(10bit) + 序列号(12bit)。
- 示例:
1629123456789(时间) +5(机器) +4095(序列)=541763281234567895。
- 示例:
- 优点:
- 高性能(单机每秒26万+),ID有序。
- 去中心化,无单点故障。
- 缺点:
- 依赖系统时钟,时钟回拨会导致ID重复。
- 机器ID需手动分配(ZooKeeper/配置中心)。
- 改进方案:
- 美团Leaf:解决时钟回拨,支持号段模式。
- 百度UidGenerator:优化时间戳分配策略。
- 适用场景:大规模分布式系统(如电商订单、IM消息ID)。
5. 号段模式(Segment,比较常用)
- 原理:从数据库批量获取ID段(如1~1000),缓存在本地逐步分配。
- 流程:
- 业务服务从数据库加载号段(
update id_generator set max_id=max_id+1000)。 - 本地内存分配ID,号段耗尽后重新获取。
- 业务服务从数据库加载号段(
- 优点:
- 减少数据库访问(TPS从千级降至个位)。
- 支持容灾,本地号段未用完时宕机不影响。
- 缺点:
- ID不连续(号段耗尽时跳跃)。
- 需解决数据库更新的并发控制(乐观锁)。
- 适用场景:中等并发,允许ID不连续的业务(如用户ID生成)。
- 举例:
CREATE TABLE id_generator ( id int(10) NOT NULL, max_id bigint(20) NOT NULL COMMENT '当前最大id', step int(20) NOT NULL COMMENT '号段的布长', biz_type int(20) NOT NULL COMMENT '业务类型', version int(20) NOT NULL COMMENT '版本号', PRIMARY KEY (`id`) ),id biz_type max_id step version 1 101 1000 2000 0 等这批号段ID用完,再次向数据库申请新号段,对max_id字段做一次update操作,update max_id= max_id + step,update成功则说明新号段获取成功,新的号段范围是(max_id ,max_id +step]。 update id_generator set max_id = #{max_id+step}, version = version + 1 where version = # {version} and biz_type = XXX 由于多业务端可能同时操作,所以采用版本号version乐观锁方式更新,这种分布式ID生成方式不强依赖于数据库,不会频繁的访问数据库,对数据库的压力小很多。
6. 其他方案
- ZooKeeper顺序节点:
- 利用ZooKeeper的持久顺序节点生成全局有序ID(如
/order/0000000001)。 - 缺点:性能低(每秒千级),不适合高并发。
- 利用ZooKeeper的持久顺序节点生成全局有序ID(如
- MongoDB ObjectId:
- 12字节 = 时间戳(4) + 机器ID(3) + PID(2) + 计数器(3)。
- 优点:轻量级,内置生成。
- 云服务方案:
- AWS DynamoDB的全局唯一ID,阿里云分布式ID服务。
- 优点:免运维,高可用。
对比总结
| 方案 | 有序性 | 性能 | 扩展性 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
| UUID | 无 | 极高 | 无限 | 无序、存储大 | 日志、临时标识 |
| 数据库自增 | 有序 | 低 | 差 | 扩展困难、性能瓶颈 | 小规模系统 |
| Redis | 有序 | 高 | 中 | 依赖Redis持久化 | 高并发订单 |
| Snowflake | 有序 | 极高 | 高 | 时钟回拨问题、机器ID管理 | 大规模分布式系统(订单) |
| 号段模式 | 局部有序 | 高 | 高 | ID不连续、需维护号段表 | 用户ID、配置项 |
选型建议
- 追求极致性能与有序性:选Snowflake或其改进版(如Leaf-Snowflake)。
- 高并发允许ID跳跃:Redis或号段模式。
- 简单快速无依赖:UUID(但需接受无序性)。
- 云环境优先:使用云厂商提供的托管服务(如AWS Global ID)。
合理选择分布式ID方案,可显著提升系统的扩展性与稳定性,支撑千万级甚至亿级数据场景。