分布式ID生成方案

  全局唯一ID就叫分布式ID,高可用低延时,ID生成响应要快。方案

UUID
数据库自增ID
数据库多主模式
号段模式
Redis
雪花算法(SnowFlake)

UUID

  本地生成无网络消耗,具有唯一性;无序的字符串,不具备趋势自增特性,长度过长16 字节128位,36位长度的字符串,存储以及查询对MySQL的性能消耗较大;

基于数据库自增ID

  基于数据库的auto_increment自增ID完全可以充当分布式ID,访问量激增时MySQL本身就是系统的瓶颈,

基于数据库集群模式

  双主模式集群,就是两个Mysql实例都能单独的生产自增ID,解决方案:设置起始值自增步长

  MySQL_1 配置:

set @@auto_increment_offset = 1;     -- 起始值
set @@auto_increment_increment = 2;  -- 步长

  MySQL_2 配置:

set @@auto_increment_offset = 2;     -- 起始值
set @@auto_increment_increment = 2;  -- 步长

  如果集群后的性能还是扛不住高并发咋办?就要进行MySQL扩容增加节点

  

 

   水平扩展的数据库集群,有利于解决数据库单点压力的问题,同时为了ID生成特性,将自增步长按照机器数量来设置。缺点:不利于后续扩容,而且实际上单个数据库自身压力还是大,依旧无法满足高并发场景。

Redis模式

  原理就是利用redis的 incr命令实现ID的原子性自增,redis有两种持久化方式RDBAOF

  • RDB会定时打一个快照进行持久化,假如连续自增但redis没及时持久化,而这会Redis挂掉了,重启Redis后会出现ID重复的情况。
  • AOF会对每条写命令进行持久化,即使Redis挂掉了也不会出现ID重复的情况,但由于incr命令的特殊性,会导致Redis重启恢复的数据时间过长。
 雪花算法(Snowflake)模式
  

 

   Snowflake生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,就是说一个Long类型占64个比特。Snowflake ID组成结构:正数位(占1比特)+ 时间戳(占41比特)+ 机器ID(占5比特)+ 数据中心(占5比特)+ 自增值(占12比特),总共64比特组成的一个Long类型。

  • 第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,生成ID都为正数,默认为0。
  • 时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,是用(当前时间戳 - 固定开始时间戳)的差值,使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
  • 工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。
  • 序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID

时间回拨问题

  获取时间的时候,可能会出现时间回拨的问题,什么是时间回拨问题呢?就是服务器上的时间突然倒退到之前的时间,不同的机器上需要同步时间,可能不同机器之间存在误差,那么可能会出现时间回拨问题

解决方案

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

  

 
posted on 2022-06-12 11:49  溪水静幽  阅读(268)  评论(0)    收藏  举报