温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

什么是分布式SnowFlakeID?如何优化SnowFlakeID?

发布时间:2020-05-27 11:18:49 来源:亿速云 阅读:697 作者:Leah 栏目:编程语言

什么是分布式SnowFlakeID?如何优化SnowFlakeID?这些问题可能是我们日常工作会见到的。通过这些问题,希望你能收获更多。下面是揭开这些问题的详细内容。

什么是SnowFlakeID

SnowFlake是twitter公司内部分布式项目采用的ID生成算法,开源后广受国内大厂的好评。由这种算法生成的ID,我们就叫做SnowFlakeID

SnowFlakeID的最大的特性就是天然去中心化,通过时间戳、工作机器编号两个变量进行配置后,通过SnowFlake算法会生成唯一的递增ID。在任何机器上,只要保证工作机器编号不同,就可以确保生成的ID唯一,且整体趋势是递增的

Snowflake的结构如下(每部分用-分开):

0 - 0000000000 0000000000 0000000000 0000000000 0 - 0000000000 - 000000000000

第一段1位为未使用,永远固定为0

第二段41位为毫秒级时间(41位的长度可以使用69年)

第三段10位为workerId(10位的长度最多支持部署1024个节点)

第三段12位为毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)

如果按照1024的满节点(1个节点就是1个部署的服务)计算,每毫秒可生成的ID序号有1024*4096=4194304个,足以满足现在绝大多数的业务情况

算法的核心如下

 ((当前时间 - 服务时间) << timestampLeftShift) 
        | (机器ID << workerIdShift) 
        | sequence;

服务时间指的是服务的开发时间,即第一个正式ID产生的时间。由于SnowFlakeID最长可用69年(因为只有41个bit,41个bit的最大值换算成年就是69年)。所以服务时间越贴近上线时间,则该算法可用时间越长。
其中sequence为递增序列,当前时间戳和上一ID生成时间戳一致时,sequence就递增1,直到4096为止。

SnowFlake有什么问题

SnowFlake很好,分布式、去中心化、无第三方依赖。但它并不是完美的,由于SnowFlake强依赖时间戳,所以时间的变动会造成SnowFlake的算法产生错误。

时钟回拨:最常见的问题就是时钟回拨导致的ID重复问题,在SnowFlake算法中并没有什么有效的解法,仅是抛出异常。时钟回拨涉及两种情况①实例停机→时钟回拨→实例重启→计算ID ②实例运行中→时钟回拨→计算ID

手动配置:另一个就是workerId(机器ID)是需要部署时手动配置,而workerId又不能重复。几台实例还好,一旦实例达到一定量级,管理workerId将是一个复杂的操作。

如何优化

时钟回拨改进避免

ID生成器一旦不可用,可能造成所有数据库相关新增业务都不可用,影响太大。所以时钟回拨的问题必须解决。

造成时钟回拨的原因多种多样,可能是闰秒回拨,可能是NTP同步,还可能是服务器时间手动调整。总之就是时间回到了过去。针对回退时间的多少可以进行不同的策略改进。一般有以下几种方案:

  1. 少量服务器部署ID生成器实例,关闭NTP服务器,严格管理服务器。这种方案不需要从代码层面解决,完全人治。
  2. 针对回退时间断的情况,如闰秒回拨仅回拨了1s,可以在代码层面通过判断暂停一定时间内的ID生成器使用。虽然少了几秒钟可用时间,但时钟正常后,业务即可恢复正常。
if (refusedSeconds <= 5) {
    try {
    //时间偏差大小小于5ms,则等待两倍时间
        wait(refusedSeconds << 1);//wait
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    currentSecond = getCurrentSecond();
}else {//时钟回拨较大
    //用其他策略修复时钟问题
}
  1. 实例启动后,改用内存生成时间。该方案为baidu开源的UidGenerator使用的方案,由于实例启动后,时间不再从服务器获取,所以不管服务器时钟如何回拨,都影响不了SnowFlake的执行。如下代码中lastSecond变量是一个AtomicLong类型,用以代替系统时间
 List<Long> uidList = uidProvider.provide(lastSecond.incrementAndGet());
  1. 以上2和3都是解决时钟实例运行中→时钟回拨→计算ID的情况。而实例停机→时钟回拨→实例重启→计算ID的情况,可以通过实例启动的时候,采用未使用过的workerId来完成。只要workerId和此前生成ID的workerId不一致,即便时间戳有误,所生成的ID也不会重复。UidGenerator采取的就是这种方案,但这种方案又必须依赖一个存储中心,不管是redismysql、zookeeper都可以,但必须存储着此前使用过的workerId,不能重复。尤其是在分布式部署Id生成器的情况下,更要注意用一个存储中心解决此问题。
以上就是SnowFlakeID以及优化方法的详细内容了,看完之后是否有所收获呢?如果想了解更多相关内容,欢迎关注亿速云行业资讯!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI