分布式系统唯一 ID 生成方案技术详解
一、分布式系统唯一 ID 的特点
- 全局唯一性:不能出现重复的 ID 号,这是最基本的要求。
- 趋势递增:在 MySQL InnoDB 引擎中使用的是聚集索引,由于多数 RDBMS 使用 B-tree 的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。
- 单调递增:保证下一个 ID 一定大于上一个 ID,例如事务版本号、IM 增量消息、排序等特殊需求。
- 信息安全:如果 ID 是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定 URL 即可;如果是订单号就更危险了,竞对可以直接知道一天的单量。所以在一些应用场景下,会需要 ID 无规则、不规则。
- 高可用性:ID 生成系统必须保证高可用,确保在任何时候都能正确生成 ID。
- 高性能:ID 生成速度要快,对本地资源消耗要小。
二、分布式系统唯一 ID 的实现方案
1. UUID
工作原理:UUID(Universally Unique Identifier)是基于当前时间、计数器(counter)和硬件标识(通常为无线网卡的 MAC 地址)等数据计算生成的唯一标识符。它由一个 32 位数的 16 进制数字组成,以连字号分隔的五组来显示,形式为 8-4-4-4-12 的 36 个字符。
优点:
- 性能非常高,本地生成,没有网络消耗。
- 全球唯一,数据迁移容易。
缺点:
- 不易于存储,UUID 太长,通常以 36 长度的字符串表示,很多场景不适用。
- 信息不安全,基于 MAC 地址生成的 UUID 算法可能会暴露 MAC 地址。
- ID 作为主键时在特定的环境会存在一些问题,比如 MySQL InnoDB 引擎下,UUID 的无序性可能会引起数据位置频繁变动,严重影响性能。
适用场景:适用于不需要 ID 有序性的场景,如会话 ID、临时文件名等。
2. 数据库生成 ID
工作原理:利用数据库的自增主键功能(如 MySQL 的 AUTO_INCREMENT),每次插入记录时自动生成递增的 ID。
优点:
- 实现简单,ID 单调自增,数值类型查询速度快。
缺点:
- 强依赖数据库,当数据库异常时整个系统不可用。
- 在分布式系统中,多个数据库实例可能生成重复 ID。
- 数据库性能瓶颈可能限制 ID 生成速度。
改进方案:
- 数据库集群模式:通过多个数据库实例设置不同的起始值和步长来生成全局唯一的 ID。例如,实例 1 从 1 开始,步长为 2;实例 2 从 2 开始,步长为 2。
- 号段模式:每次从数据库取出一个号段范围(如 1000-2000),在内存中分配,使用完后再获取下一段。这样可以减少对数据库的直接访问,提升生成性能。
适用场景:适用于单机数据库或主从复制的数据库环境,不适合分布式数据库。
3. Redis 生成 ID
工作原理:利用 Redis 的原子性操作(如 INCR 命令)生成递增的唯一 ID。
优点:
- 不依赖于数据库,灵活方便,且性能优于数据库。
- 数字 ID 天然排序,对分页或者需要排序的结果很有帮助。
缺点:
- 需要依赖 Redis 服务,若 Redis 故障,ID 生成受影响。


