深入解析分布式ID生成机制

一、概述

背景:随着数据库数据量的增长, 基于性能原因需要进行分库分表,分库分表会导致主键ID重复问题。
特点:

  1. 全局唯一性[必须];
  2. 趋势递增[非必须]。由于互联网大部分采用Mysql的Innodb引擎,因此保持有序主键ID有利于insert的效率;
  3. 单调递增[非必须]。保证下一个ID大于上一个ID,可以保证事务版本号,排序等特殊场景需求;
  4. 信息安全[非必须]。如果ID是连续的,容易被爬虫爬取数据。

二、实现方案

2.1 Java原生UUID

Universally Unique Identifie,通用唯一标识码的简称。为了保证唯一性,通用UUID规范使用MAC地址、时间戳、名字空间以及随机数等元素,保证UUID的唯一性。UUID通常由32个16进制数字,以"-"分成5段,形式为8-4-4-4-12,因此UUID理论上总数为16^32个。
优点:性能非常高,本地生成,不依赖网络;
缺点:ID是随机生成的,不连续的,影响性能。

2.2 自增ID + 步长

利用数据库自增主键,不同机器设置不同步长,步长和机器数相同(参考主键生成策略)。
优点:满足全局ID唯一性,同时利用了数据库自增主键ID,提高了性能;
缺点:

  1. 只能趋势递增,无法保证单调递增;
  2. 机器数是固定死的,一旦需要扩容,那么需要重新设置步长。

2.3 号段模式

从数据库中获取一个号段范围,比如说[1,1000]生成1到1000的自增ID加载到内存中。需要额外设置一张表记录号段相关的信息。
优点:由比较成熟的方案。类似于百度Uidgenerator,美团Leaf
缺点:依赖于数据库实现。

2.4 Redis实现

通过INCR和INCRBY类似的自增原子命令,由于Redis单线程特点,可以保证ID的唯一性和有序性。
优点:Redis性能比较好,且可以保持唯一性和有序性
缺点:

  1. 在并发请求高的情况下,需要Redis集群部署,这就要求和Mysql类似,设置步长;
  2. 需要依赖Redis实现,引入Redis组件

2.5 雪花算法(SnowFlake)

前言:是Twitter开源的由64位整数组成分布式ID,性能较高,并且在单机上递增。
在这里插入图片描述
雪花算法总共64位,具体信息为:

  1. 1bit是符号位,始终是0,表示为正数;
  2. 41bit是时间戳,单位位毫秒。41位的二进制可以使用69年,且时间是永恒递增的,所以ID总趋势是递增的
  3. 10bit是机器标识。可以全部当作机器ID,也可以标识【机房ID + 机器ID】,最多可以表示位1024台机器;
  4. 12bit是计数序列号,即在同一台机器同一时间前提下,还可以生成不同的ID,12bit理论上可以生成4096个ID。

优化点1:

由于41位是时间戳,我们的时间计算是从1970年开始的,只能使用69年。因此,可以考虑将1970修改为项目上线时间,为了不浪费,其实我们可以用【时间的相对值】,也就是以项目开始的时间为基准时间,往后可以使用69年。获取唯一ID的服务,对处理速度要求比较高,所以我们全部使用【位运算以及位移】操作,获取当前时间可以使用System.currentTimeMillis()。

优化点2:时间回拨问题
什么是时间回拨问题呢?就是服务器上的时间突然倒退到之前的时间。

  1. 人为原因,把系统环境的时间改了。
  2. 有时候不同的机器上需要同步时间,可能不同机器之间存在误差,那么可能会出现时间回拨问题。

解决方案:

  1. 回拨时间小的时候,不生成 ID,循环等待到时间点到达;
  2. 如果间隔过大,阻塞等待,肯定是不可取的,因此要么超过一定大小的回拨直接报错,拒绝服务,或者有一种方案是利用拓展位,回拨之后在拓展位上加1就可以了,这样ID依然可以保持唯一。但是这个要求我们提前预留出位数,要么从机器id中,要么从序列号中,腾出一定的位,在时间回拨的时候,这个位置+1

优点:

1. 保证了全局唯一,且在单机器上趋势是递增的,并发场景下性能依然优异;
2. 可根据自身业务特性分配bit位,比较灵活。

缺点:

1. 强依赖时钟;
2. 分布式下虽然趋势递增,但不是单调递增的

三、总结

最佳实践:一般来说,继续采用Mysql的主键ID当作逻辑主键ID,没任何含义;使用分布式全局ID当做业务主键ID,定义为no_null和unique。

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃花猿

客官,赏点打酒钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值