浅谈常用的分布式ID的设计方案以及Snowfake是否受冬令时切换影响

分布式ID定义

  1. 全局唯一:区别于单点系统的唯一,全局是要求分布式系统内唯一。
  2. 有序性:通常都要保证生成的ID是有序递增的。例如,在数据库存储场景中,有序ID便于确定数据位置,往往更加高效。

典型实现方案

基于数据库自增序列的实现

这种方式的优缺点都非常明显,好处是简单易用,但是在扩展性和可靠性方面存在局限性。
优点 : 对于数据库自增方案,除了实现简单,它生成的ID还能够保证固定步长的递增,使用很方面。对于单点故障的解决方案是利用Master-slave的主从复制模式。
缺点: 但是,因为每次获取一个ID就会触发数据库的写请求,是一个代价高昂的操作,构建高扩展性、高性能解决方案比较复杂,性能上限明显,更不用谈扩容等场景的难度了,与此同时,保证数据库方案的高可用性也存在挑战,数据库可能发生宕机,即使采取主从热备等各种措施,也可能出现ID重复的现象。

UUID方案

UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符。UUID在其他语言中也叫GUID,在java中,生成UUID的代码很简单:

String uuid = UUID.randomUUID().toString();

一个UUID是16字节长的数字,一共128位。通常以36字节的字符串表示,比如:3a5c3b08-5501-4a1b-8b38-446e73582375。 使用的时候,可以把中间的4个中划线去掉,剩下32位字符串:3a5c3b0855014a1b8b38446e73582375。

UUID经由一定的算法机器生成,为了保证UUID的唯一性,规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。UUID的只能由计算机生成。
优点 : 本地生成ID,不需要进行远程调用,时延低,性能高。
缺点 : UUID过长,16字节128位,通常以36长度的字符串表示,很多场景不适用,比如,由于UUID没有排序,无法保证趋势递增,用做数据库索引字段的效率就很低,太长了,存储空间大,新增记录存储入库时性能差。

Redis方案

Redis 有计数器实现,利用此功能可以实现分布式ID。(increment)
优点 : 性能好,有序,可读性好。
缺点 : 缺点是为了防单点故障,需要引入Redis集群,增加了额外编码和配置的工作量。

Snowflake方案

基于Twitter早期开源的Snowfake的实现,以及相关改动方案。这是目前应用相对比较广泛的一种方式,其结构定义示意图:
在这里插入图片描述
整体长度通常是64 (1 + 41 + 10+ 12 = 64)位,适合使用Java语言中的long类型来存储。

符号位说明:第一位为不能为负的符号位:0

时间戳说明:41位记录时间戳timeMillis,当前系统时间,Java 中通常用System.currentTimeMillis()获取long 型数字,转化二进制刚好41位。存在2038年问题

工作机器ID说明
10位记录工作机器id;即datacenterId (5位数据id) + workerId (5位机器id)
datacenterId 与 workerId的最大值十进制值是31(不能为负数)
原因:5位数的最大二进制表示: 0001 1111 —> 十进制:31
序列号说明:

12位自增序列号sequence
Sequence的最大十进制值是4095(不能为负数)
原因:12位数的最大二进制表示:1111 1111 1111 —> 十进制:4095

核心算法
计算所需默认常量
默认固定时间twepoch: 1488834975643(毫秒)(小于当前时间即可,不能出现负数)
时间戳偏移位数 timestampLeftShift:22(给5位机器id、5位数据id、12位序列号移除位置)
数据id偏移位数 datacenterIdShift:17(给5位数据id、12位序列号移除位置)
机器id偏移位数 workerIdShift:12(给12位序列号移除位置)
开始计算
一,需要输入的条件(以这4个数据为例):
当前时间 timwstamp:1523244373577(毫秒)
机器id workerId:8(本机ip)
数据id datacentId:12(当前进程Hashmap)
序列号sequence:123(自增序列号)
二,计算:
计算公式:

return ((timwstamp-twepoch) << timestampLeftShift) | (datacentId << datacenterIdShift) | (workerId << workerIdShift) | sequence;

优点 : Snowfake方案的好处是算法简单,依赖也非常少,生成的序列可预测,性能也非常好。
缺点 : 时钟偏斜问题(Clock Skew)。我们知道普通的计算机系统时钟并不能保证长久的一致性,可能发生时钟回拨等问题,这就会导致时间戳不准确,进而产生重复ID。从理论上来说,类似Snowfake的方案由于时间数据位数的限制,存在与2038年问题相似的理论极限.

Snowfake是否受冬令时切换影响

我认为没有影响,你可以从Snowfake的具体算法实现寻找答案。我们知道Snowfake算法的Java实现,大都是依赖于System.currentTimeMillis(),这个数值代表什么呢? 从Javadoc可以看出,它是返回当前时间和1970年1月1号UTC时间相差的毫秒数,这个数值与夏/冬令时并没有关系,所以并不受其影响。

原创文章 29 获赞 81 访问量 1万+

猜你喜欢

转载自blog.csdn.net/cuixhao110/article/details/103493922