为什么需要分布式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;

雪花算法原理图:

image-20201230225916882

常见雪花算法改造

百度(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提供httptinyid-client两种方式接入。