分布式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有两种持久化方式RDB和AOF
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
时间回拨问题
获取时间的时候,可能会出现时间回拨的问题,什么是时间回拨问题呢?就是服务器上的时间突然倒退到之前的时间,不同的机器上需要同步时间,可能不同机器之间存在误差,那么可能会出现时间回拨问题
解决方案
- 回拨时间小的时候,不生成 ID,循环等待到时间点到达。
- 上面的方案只适合时钟回拨较小的,如果间隔过大,阻塞等待,肯定是不可取的,因此要么超过一定大小的回拨直接报错,拒绝服务,或者有一种方案是利用拓展位,回拨之后在拓展位上加1就可以了,这样ID依然可以保持唯一。但是这个要求我们提前预留出位数,要么从机器id中,要么从序列号中,腾出一定的位,在时间回拨的时候,这个位置
+1。
立志如山 静心求实
浙公网安备 33010602011771号