分布式唯一id

Posted by Laiaike on 2024-04-26

分布式唯一id

1. UUID

32个16进制数,128位,8-4-4-4-12

优点:

  • 性能高,本地生成,无网络消耗

缺点:

  • 不宜存储:太冗长
  • 基于MAC地址生成,可能造成MAC地址泄露
  • 无序,不适合当主键,影响性能

2. snowflake

1(sign标识位)- 41(时间戳)- 10(workerId,数据中心+工作机器)- 12位自增序列

缺点:

生成id可能重复,原因可能为:

  • 时间回拨
  • 机器id重复

对于机器id重复,确保机器id不同即可;对于时间回拨产生的时间戳重复的问题,有几种解决方式:

  1. 阻塞id生成,直至回到回拨前最大时间戳的时间之后;
  2. 记录回拨前最大时间戳,回拨后从该时间戳开始自增。

3. 分布式数据库生成

多台部署,设置不同的初始值,相同步长

缺点:水平扩展困难,数据库访问压力大,每次获取ID都要读写一次数据库

4. Leaf-segment

https://tech.meituan.com/2017/04/21/mt-leaf.html

基于3中使用数据库生成的方案进行修改:每次获取ID都要读写一次数据库造成数据库压力较大,改为利用proxy server批量获取,每次获取一个segment的值,号段值用完后再去数据库获取新的segment。如step=1000,初始值为0,即申请0-1000时申请读写一次数据库,号段值消耗完才重新申请新的号段。

优点:

  1. 水平扩展方便,性能高效
  2. 生成ID趋势递增
  3. 容灾性高:服务内部有号段缓存,短时间DB宕机可正常提供服务。

缺点:

  1. 节点号段内数据耗尽需要申请新的号段,会出现毛刺
  2. DB宕机会造成系统不可用。

5. Leaf-snowflake

6. UIDGenerator(解决了时钟回拨问题)

基于snowflake生成机制,通过消费未来时间克服算法的并发限制。UIDGenerator提前生成ID并缓存到RingBuffer中。

可以根据业务调整占用位数:

  1. DefaultUIDGenerator
  2. CachedUIDGenerator

CachedUidGenerator方式主要通过采取如下一些措施和方案规避了时钟回拨问题和增强唯一性:

自增列:UidGenerator的workerId在实例每次重启时初始化,且就是数据库的自增ID,从而完美的实现每个实例获取到的workerId不会有任何冲突。

RingBuffer:UidGenerator不再在每次取ID时都实时计算分布式ID,而是利用RingBuffer数据结构预先生成若干个分布式ID并保存。

时间递增:传统的雪花算法实现都是通过System.currentTimeMillis()来获取时间并与上一次时间进行比较,这样的实现严重依赖服务器的时间。而UidGenerator的时间类型是AtomicLong,且通过incrementAndGet()方法获取下一次的时间,从而脱离了对服务器时间的依赖,也就不会有时钟回拨的问题(这种做法也有一个小问题,即分布式ID中的时间信息可能并不是这个ID真正产生的时间点,例如:获取的某分布式ID的值为3200169789968523265,它的反解析结果为{“timestamp”:”2019-05-02 23:26:39”,”workerId”:”21”,”sequence”:”1”},但是这个ID可能并不是在”2019-05-02 23:26:39”这个时间产生的)。

add:

Redis自增:increment

数据库自增:单独一张表