为什么需要分布式ID?
传统的ID生成方式一般使用数据库自增,这样有序且长度可控,但是在分布式环境里,往往因库表数据过大而需要分库、分表,这样继续使用自增主键就会出现主键冲突问题。一般需要一个单独的机制或服务来生成一套全局的ID,这样的ID也叫分布式ID。
分布式ID目前有哪些常用做法?分别有什么优缺点?
UUID;
优点:生成方式简单,无需第三方服务,可移植性好。
缺点:长度较长,无序ID,插入数据库用作主键性能不佳。
数据库自增主键(单机/集群),其他服务每次查询此最新值。
优点:获取简单,有序ID;下次生成ID可预期。
缺点:需要依赖数据库,可移植性差。集群环境下需要给每台设置步长,维护时可能需要停机。
号段模式,每次数据库保存起止ID位置,客户端请求时拿到范围后本地维护,用尽后再拿新的号段
优点:有序ID;性能较好;不强依赖数据库,自增下放至本机可自行维持一定时间;
缺点:很难保证ID不同号段的时间先后顺序(A服务先拿号段,却较后用完号段);容易造成ID空洞;
Redis incr命令原子自增(和数据库自增类似)
推荐使用
优点:使用简单;效率极高;有序ID;
缺点: 引入了redis依赖;
需要考虑自增ID持久化问题:
RDB
模式下快照未来得及持久化会出现ID重复。
AOF
模式下不会ID重复,但会由于incr
命令过多恢复数据时间过长。雪花算法
推荐使用
优点:使用简单;效率极高;有序ID;可移植性强;
缺点:生成ID依赖本地时钟,如果时钟更正或倒退,会导致雪花算法拒绝生成ID;
雪花算法原理图:
常见雪花算法改造
百度(uid-generator)
uid-generator
是由百度技术部开发,项目GitHub地址 github/uid-generator
uid-generator
是基于Snowflake
算法实现的,与原始的snowflake
算法不同在于,uid-generator
支持自定义时间戳
、工作机器ID
和 序列号
等各部分的位数,而且uid-generator
中采用用户自定义workId
的生成策略。
uid-generator
需要与数据库配合使用,需要新增一个WORKER_NODE
表。当应用启动时会向数据库表中去插入一条数据,插入成功后返回的自增ID就是该机器的workId
数据由host,port组成。
对于uid-generator ID组成结构:workId
,占用了22个bit位,时间占用了28个bit位,序列化占用了13个bit位,需要注意的是,和原始的snowflake
不太一样,时间的单位是秒,而不是毫秒,workId
也不一样,而且同一应用每次重启就会消费一个workId
。
美团(Leaf)
Leaf
由美团开发,github地址:github/Leaf
Leaf
同时支持号段模式和snowflake
算法模式,可以切换使用。
滴滴(Tinyid)
Tinyid
由滴滴开发,Github地址:github/tinyid
Tinyid
是基于号段模式原理实现的与Leaf
如出一辙,每个服务获取一个号段(1000,2000]、(2000,3000]、(3000,4000]
Tinyid
提供http
和tinyid-client
两种方式接入。