教你如何避开雪花算法的坑

教你如何避开雪花算法的坑!

https://gitee.com/automvc/bee/blob/master/src/main/java/org/teasoft/bee/distribution/GenId.java

 

public interface GenId

分布式环境下生成全局唯一数字id.Generate global unique id number in distributed environment. GUID : Global Unique ID. 分段模式与雪花到底有什么区别? 一个是依赖DB,一个是依赖时间的. 一个是取的号码可以一直连续递增的;一个是趋势递增,会因workerid的原因产生的ID号是会跳很大一段的. 依赖于DB的号段模式,当多个节点一起拿号时,最终落库的ID还是不能连续的。 雪花ID适合做分布式数据库表主键吗?它只保证递增,没保证连续。 改进目标: 能不能找到一种,既不依赖DB,也不依赖时间的ID生成算法呢?答案是,肯定有的,这是我们努力的方向!

---------------------------------------------

org.teasoft.honey.distribution.PearFlowerId

改进的雪花算法——姑且称为梨花算法(PearFlowerId)吧 (忽如一夜春风来,千树万树梨花开)。

改进目标:解决雪花算法的时钟回拨问题;部分避免机器id重复时,号码冲突问题。

long型的64位分成以下几个部分组成:

符号位:1位

时间:31位 (精确到秒)够用68年

段号(批次号):3位 每秒可分为8个段

机器号:10位 最多支持1024台机器

序列号:19位 可表示:0--524287

注:根据情况,机器号可以调整到最后部分。

每个机器,每秒可生成4.19w个id(4194304).

经过调整,时间只对秒灵敏,成功回避了服务器间几百毫秒的时间误差引起的时间回拨问题;若第59秒的8个段号没有用完,

则当润秒来临时,还可继续使用。另外具体实现上,可设置一定的秒数(如3秒)内提前消费。比如第10秒的号码,在800毫

秒用完了,可以继续使用第11秒的号码。这样,下1秒用的号码不是很多时,就可以借给上1秒使用。

以上的方案是与时间强相关的。若某一段时间内的号码没用使用,也会浪费掉。当在分布式DB的表主键这种应用场景时,

只需要全局id不重复,且是递增的。类似这种场景,可以设计成时间不相关的。

供分布式DB表主键等类似场景使用,不浪费号码的方案。long型的64位分配还是一样。只不过,取号时,是取上一个号码加1,

而不用管现在的时间是什么时候。当突然down机时,重启又获取当前的时间,重新开始分派号码;这时之前节省下的号码就被浪

费掉了。为解决这个问题,可以在一段时间或分派一定数量的号(如10000),就将当前分派的号码记录到日志,或同步到DB表,

等重启时,可以设置初始值。实现上,还是要控制分派的速度,若每秒几百万的号不够用,可用表名分隔命名空间,每个表单独取

自己的号;即使号码够用,也可以这样做,因为这样得到的号在同一张表里就比较连续,而不只是递增而矣。当各个机器分派的id

速度相差太大时,各机器得到的id大小就比较乱;这种问题,可以设置负载均衡,让每台机器轮流出号。

机器id重复的问题。当两台机器的id一样时,分派的号就会重复。若0-7八个段号(段号3位),每次都是从0-3随机获取一个

开始的段号,比方说获取到2,那重复机器id的服务要是获取到0或1的段号就可以避免号码重复的冲突。当然了,这都是基于每秒用

不完号码的情况下的。可以循环使用段号,如获取到3,那就从3-7,0,1,2这样使用段号,后面0,1,2这几个段号要是分派出去,

号码就不递增了。具体怎么用,还是要根据自己的情况做取舍。

---------------------------------------------

org.teasoft.honey.distribution.SerialUniqueId 在一个workerid内连续唯一的ID生成方法(绝对连续单调递增,全局唯一).Serial Unique Id in one workerid. 优点:连续唯一;不依赖时钟. 在DB内实现,可达到分布式全局唯一ID在DB内自增长;在同一个workerid内,获取的ID号,可以满足连续单调递增唯一. Advantages:continuous and unique;less clock dependent.Implemented in dB, it can achieve auto increment of distributed global unique ID in dB. The ID number get in the same workerid can satisfy continuous monotonic increasing uniqueness. 缺点/Shortcoming:worker1's ID 

---------------------------------------------

org.teasoft.honey.distribution.OneTimeSnowflakeId OneTimeSnowflakeId,进一步改进了梨花算法。 不依赖时间的梨花算法,Workerid应放在序号sequence的上一段,且应用SerialUniqueId算法,使ID不依赖于时间自动递增。 使用不依赖时间的梨花算法OneTimeSnowflakeId,应保证各节点大概均衡轮流出号,这样入库的ID会比较有序,因此每个段号内的序列号不能太多。 支持批获取ID号。可以一次取一批ID(即一个范围内的ID一次就可以获取了)。可以代替依赖DB的号段模式。 应用订单号等有安全要求的场景,可随机不定时获取一些批的号码不用即可。 考虑到2019年双11的峰值不超过55万笔/秒, 因此419w/s这个值已可以满足此苛刻要求;采用testSpeedLimit()检测平均值不超过419w/s这个值即可,而且在空闲时 段省下的ID号,还可以在高峰时使用。

 

https://gitee.com/automvc/bee/blob/master/src/main/java/org/teasoft/bee/distribution/GenId.java


版权声明:本文为abckingaa原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。