Save Load
GitHub 切换暗/亮/自动模式 切换暗/亮/自动模式 切换暗/亮/自动模式 返回首页

Java 分布式唯一 Id生成方案

分布式唯一ID生成方案

整个系统ID唯一 ID是数字类型,而且是趋势递增的 ID简短,查询效率快

1、UUID

优点:

  • 代码实现简单。
  • 本机生成,没有性能问题
  • 因为是全球唯一的ID,所以迁移数据容易

缺点:

  • 每次生成的ID是无序的,无法保证趋势递增
  • UUID的字符串存储,查询效率慢
  • 存储空间大
  • ID本事无业务含义,不可读

应用场景:

  • 类似生成token令牌的场景
  • 不适用一些要求有趋势递增的ID场景

2、MySQL主键自增

这个方案就是利用了MySQL的主键自增auto_increment,默认每次ID加1。

优点:

  • 数字化,id递增
  • 查询效率高
  • 具有一定的业务可读

缺点:

  • 存在单点问题,如果mysql挂了,就没法生成iD了
  • 数据库压力大,高并发抗不住

3、MySQL多实例主键自增

这个方案就是解决mysql的单点问题,在auto_increment基本上面,设置step步长 image

每台的初始值分别为1,2,3…N,步长为N(这个案例步长为4)

优点:

  • 解决了单点问题

缺点:

  • 一旦把步长定好后,就无法扩容;而且单个数据库的压力大,数据库自身性能无法满足高并发

应用场景:

  • 数据不需要扩容的场景

4、雪花 snowflake 算法

这个算法网上介绍了很多。雪花算法生成64位的二进制正整数,然后转换成10进制的数。64位二进制数由如下部分组成: image

  • 1位标识符:始终是0
  • 41位时间戳:41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截 )得到的值,这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的
  • 10位机器标识码:可以部署在1024个节点,如果机器分机房(IDC)部署,这10位可以由 5位机房ID + 5位机器ID 组成
  • 12位序列:毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号

优点:

  • 此方案每秒能够产生409.6万个ID,性能快
  • 时间戳在高位,自增序列在低位,整个ID是趋势递增的,按照时间有序递增
  • 灵活度高,可以根据业务需求,调整bit位的划分,满足不同的需求

缺点:

  • 依赖机器的时钟,如果服务器时钟回拨,会导致重复ID生成 -在分布式场景中,服务器时钟回拨会经常遇到,一般存在10ms之间的回拨;小伙伴们就说这点10ms,很短可以不考虑吧。但此算法就是建立在毫秒级别的生成方案,一旦回拨,就很有可能存在重复ID。

5、Redis生成方案

利用redis的incr原子性操作自增,一般算法为:

年份 + 当天距当年第多少天 + 天数 + 小时 + redis自增

优点:

  • 有序递增,可读性强

缺点:

  • 占用带宽,每次要向redis进行请求

性能还可以,如果对性能要求不是太高的话,这个方案基本符合要求。

但不完全符合希望id从 1 开始趋势递增。(当然算法可以调整为 就一个 redis自增,不需要什么年份,多少天等)。

6、小结

以上介绍了常见的几种分布式ID生成方案。一线大厂的分布式ID方案绝没有这个简单,他们对高并发,高可用的要求很高。

如Redis方案中,每次都要去Redis去请求,有网络请求耗时,并发强依赖了Redis。这个设计是有风险的,一旦Redis挂了,整个系统不可用。

而且一线大厂也会考虑到ID安全性的问题,如:Redis方案中,用户是可以预测下一个ID号是多少,因为算法是递增的。

这样的话竞争对手第一天中午12点下个订单,就可以看到平台的订单ID是多少,第二天中午12点再下一单,又平台订单ID到多少。这样就可以猜到平台1天能产生多少订单了,这个是绝对不允许的,公司绝密啊。