分布式ID
常见解决方案
在分布式系统中,生成全局唯一ID是非常重要的,这里通过几种解决方案
- UUID:(Universally Unique Identifier)是基于当前时间、计数器(counter)和硬件标识(通常为无线网卡的MAC地址)等数据计算生成的。它包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的36个字符,可以生成全球唯一的编码并且性能高效。但是,UUID在实际应用过程中一般不采用,原因包括存储成本高、信息不安全以及不符合MySQL主键要求
- 数据库自增ID:利用Mysql的特性ID自增,可以达到数据唯一标识,但是分库分表后只能保证一个表中的ID的唯一,而不能保证整体的ID唯一。为了避免这种情况,我们有以下两种方式解决该问题:主键表和ID自增步长设置
- 号段模式:号段模式是当下分布式ID生成器的主流实现方式之一。其原理如下:号段模式每次从数据库取出一个号段范围,加载到服务内存中。业务获取时ID直接在这个范围递增取值即可。等这批号段ID用完,再次向数据库申请新号段,对max_id字段做一次update操作,新的号段范围是 (max_id ,max_id +step)。由于多业务端可能同时操作,所以采用版本号version乐观锁方式更新
- Redis INCR:基于全局唯一ID的特性,我们可以通过Redis的INCR命令来生成全局唯一ID
- 雪花算法:Snowflake 中文的意思是雪花,所以常被称为雪花算法,是 Twitter 开源的分布式 ID 生成算法。Twitter 雪花算法生成后是一个 64bit 的 long 型的数值,组成部分引入了时间戳,基本保持了自增
优缺点
| 优点 | 缺点 | |
|---|---|---|
| UUID | 代码实现简单、没有网络开销,性能好 | 占用空间大、无序 |
| 数据库自增ID | 利用数据库系统的功能实现,成本小、ID自增有序 | 并发性能受Mysql限制、强依赖DB,当DB异常时整个系统不可用,致命 |
| Redis INCR | 性能优于数据库、ID有序 | 解决单点问题带来的数据一致性等问题使得复杂度提高 |
| 雪花算法 | 不依赖数据库等第三方系统,性能也是非高、可以根据自身业务特性分配bit位,非常灵活 | 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。 |
| 号段模式 | 数据库的压力小 | 单点故障ID不连续 |
UUID
UUID是一个长度为128位的标志符,能够在时间和空间上确保其唯一性。可让分布式系统可以不借助中心节点,就可以生成唯一标识, 比如唯一的ID进行日志记录
由于UUID是一个128位的长的标志符,为了便于阅读和显示,通常会将这个大整数转换成32(不包含连接符)个十六进制字符组成的字符串形式
结构
| 字段 | hexOctet(字节) | 位置 | 备注 |
|---|---|---|---|
| time_low | 4 | 0-3 | 时间戳 的低位部分 |
| time_mid | 2 | 4-5 | 时间戳的中间部分 |
| time_hi_and_version | 2 | 6-7 | 时间戳高位部分与 版本 字段,其中12位代表时间戳的高12位,4位则用来标识UUID的版本号 |
| clock_seq_hi_and_reserved | 1 | 8 | 时钟序列 高位与 保留位 |
| clock_seq_low | 1 | 9 | 时钟序列低位 |
| node | 6 | 10-15 | 节点标识符,提供空间唯一性,通常基于MAC地址或随机数生成,以确保全局范围内的唯一性 |
UUID是通过时间和空间两层上来保证其唯一性
- 时间:时间戳+时钟时序
- 空间:节点标标志符
雪花算法
优点
- 高性能高可用:生成时不依赖于数据库,完全在内存中生成
- 高吞吐:每秒钟能生成数百万的自增 ID
- ID 自增:存入数据库中,索引效率高
缺点
- 依赖与系统时间的一致性,如果系统时间被回调,或者改变,可能会造成 ID 冲突或者重复
组成
- 不使用:1bit,最高位是符号位,0 表示正,1 表示负,固定为 0
- 时间戳:41bit,毫秒级的时间戳(41 位的长度可以使用 69 年)
- 标识位:5bit 数据中心 ID,5bit 工作机器 ID,两个标识位组合起来最多可以支持部署 1024 个节点
- 序列号:12bit 递增序列号,表示节点毫秒内生成重复,通过序列号表示唯一,12bit 每毫秒可产生 4096 个 ID。
- 通过序列号 1 毫秒可以产生 4096 个不重复 ID,则 1 秒可以生成 4096 * 1000 = 409w ID
默认的雪花算法是 64 bit,具体的长度可以自行配置。如果希望运行更久,增加时间戳的位数;如果需要支持更多节点部署,增加标识位长度;如果并发很高,增加序列号位数
生成的ID重复时的条件
- 服务通过集群的方式部署,其中部分机器标识位一致。
- 业务存在一定的并发量,没有并发量无法触发重复问题。
- 生成 ID 的时机:同一毫秒下的序列号一致
参考文章:
分布式ID
https://lzhengjy.github.io/2024/07/10/分布式ID/