作者最近在实现雪花算法生成主键,看了不少文章。个人觉得雪花算法的最大的优点是有序(减少数据库的页分裂页合并)。雪花算法本身很简单,但他依赖于时间,也就是机器或容器的时间一回拨就出现问题了。网上也出现了不少关于如何解决回拨的问题。我记录一下本次实现雪花主键的过程。

先定个目标

实现雪花算法的主键

提供不同策略的时钟回拨解决方法

尽量避免完全自增,导致ID规则被发现

初识雪花算法

雪花算法生成的id的结果是一个64bit的整数,结构如下(引用网上的图片):

​由此可以看出他是一个较大的正整数,在同一毫秒内,他可以生成4096个ID(12位序列号,12个1的二进制就是4095,再加个0)。所以适合并发量较大的有序ID。

​由于有41位的时间戳,所以非常依赖应用程序的时间,如果时钟发生回拨,会造成前面41位的二进制重复,从而导致ID重复,这是不可取的。

时间回拨解决思路

思路一

​我们的目标是想让ID有序(自增也行)。但我们的并发不可能一直很高,几乎不可能每一毫秒都是4096个插入。所以肯定有相对来说有一毫秒内用不完的序列。所以当时我就做了一个想法,我的时间戳部分能不能等这个毫秒用完了序列号再增加一毫秒。等时钟回拨的时候,我不看当前时间,我只看到了哪个时间戳。这种方式能解决时间回拨问题,但有个致命缺陷。因为你的ID永远是有规律的。太容易被爬走了。如果你以这个ID作为商家ID或其它相对公开信息的ID,很容易被人爬走信息。这种想法暂时放弃。

思路二

​假设一般情况下我们不会随意回拨赶时间,这也确实是的,谁也不会没事找事把时间改来改去,特别是生产上。所以我们假设时间回拨很小,回拨的几率也很小,而且这个回拨的时候在客户的忍耐范围之内。比如回拨了1秒钟,我们的应用允许有2秒的请求延迟,所以这个在我们的容忍范围内,我可以让时间过了这一秒,再生成主键。这是可取的。我们称这种策略叫"等待",也叫WAITING

​这种策略仅限于客户或应用可以容忍一定时间内的时钟回拨,如果回拨超时一定时间内,我们可以抛出异常,让程序响应异常。

​此种策略应用于数据量大,但并发不是特别大的情况。

思路三

​我们仔细观察ID生成规则,会发现有一个10位的工作机器ID,我们常常把他分为两块:前5位是datacenterId,也有人叫roomId,我们这里叫他groupId;后5位是workerId,就是具体的工作ID,这两块可以有1024种组合。如果我们不是大型微服务应用,这个1024个组合用不完,那我们能不能拿出一部分作为备用组合。这样在时间回拨的时候启用备用组合。这种叫“启用备用ID”,我们叫Extra workerId

​这种策略仅限于工作机器的ID组合用不完,并且时钟不会回拨到同一时间点或区间的情况。如果我们在一个时间点(假设是1)一开始是由主workerId生成ID,后来由于时钟回拨,又跳回时间点1,我们启用备用extra workerId。但是又发生时钟回拨,又将时钟跳回时间点1,这个时候workerId和extra workerId都用过了,在这个时间点已经没有任何workerId可用了,所以必然会造成ID重复。

​这种策略可用于workerId用不完,且不会回拨至同一个时间点(区间)的情况。

思路四

​我们如果只是用当前时间戳,作为前41位,因为位数固定,所以相对来说这个ID使用的时间较短。但是如果我们减去一个差值(这里叫偏移量),用相对时间,这样我们使用的时候就会长很多。因为减去一部分,使ID变小,这样ID的增长空间才会变大,使用时间变长。

​好,我们假设也引入了偏移量这个概念。如果时钟回拨,会产生什么现象呢?时钟一回拨ID变小,导致ID会重复,所以我们这个时候只要想办法让ID再次变大,变成和回拨前一样的大小或比回拨前稍微大一点。那如何处理呢,刚刚我们引进了偏移量这个概念,时钟回拨我们会让ID变小,但减小偏移量我们会让ID变大,所以我们通过修改偏移量的方式达到让ID回到原来的轨道上来。

​肯定又有人说了你在内存里修改了偏移量,下次重启的时候咋办,应用肯定会重启啊。是的,如果应用重启了,如果重启的间隔时间大于回拨时间。这个时候是没有问题,如果小于,会出现ID重复的情况。这个时候我们还有办法吗?答案是有的。我们可以在时钟回拨后将偏移量存起来,然后项目重启后再加载进来。这样就可以了。

​这种策略可以用于并发量很大的场景。对于同一张表同一个应用他的存储一定是一个,不能乱。否则可能会出现ID重复。

总结

​我们提出以上几点时钟回拨的解决思路。看似解决了一些问题。可是问题又来了。对于一个应用来说有可能有不同表都需要生成ID。这个时候我们来回顾一下,雪花算法的组成部分:时间戳,机器ID,12位序列号。

时间戳:对于同一个应用来说只有一个,所以是共用的

时间偏移量,共用,一旦时钟回拨,所有ID生成器的偏移量都要变小。理论上保存的时候只要保存一份即可。但实际上最好是多份,因为不是所有ID生成器都能发现时钟回拨,或者发现时钟回拨的时间不一样,这个时候建议保存多份。

机器ID:对于同一个应用来说也是一样的,所以也是共用的

备用机器ID,共用,一旦时钟回拨,所有ID生成器的备用ID都要切到备用机器ID,但实际上也建议是多份,不是所有ID生成器都能发现时钟回拨。

序列号:不同表的序列号肯定不一样。所以为每张表(ID生成器)定义一个squence

本次作者就写到这里。相关代码已经上传至: github.com/zhouxx/boot… 模块之boot-plus-mybatis-jpa的主键实现部分。欢迎一起讨论。

C语言雪花算法,记一次雪花算法的实现相关推荐

  1. 雪花算法及运用PHP,雪花算法生成全局唯一ID,参考了下网上雪花算法生成规则,机器ID和序列号自动获取 理论上毫秒可生成 1024*4096个唯一ID

    任务要求毫秒生成10000个唯一ID 研究了下twitter/snowflake的算法思想: 参考了下网上雪花算法生成规则,把数据中心和机器编号整合一起,变成10位机器ID, 机器ID和序列号自动获取 ...

  2. python 推荐系统算法,Python用户推荐系统minkowski算法的实现

    Python用户推荐系统minkowski算法的实现 #-*- coding: utf-8 -*- ''' python: www.iplaypy.com @author: Jekey 欧几里得距离 ...

  3. 雪花算法原理_迈向雪花的大统一理论,雪花结晶理论之父提出新思路

    冬日漫漫,而当云层够厚.气温够低时,云中的水分便会凝结成冰,降为雪花,为世界增添一分纯洁的白. 关于雪花的形状,虽然早在公元前 135 年,我国汉代文学家韩殷就对此提出过疑问,写道:"植被之 ...

  4. 智能手机计步算法c语言实现,【转载】智能手机计步器算法的实现

    现 在的智能手机嵌入了一些微小的传感器,比如重力传感器.光传感器.声音传感器等.如何有效地利用这些传感器来开发一些应用,是一个值得深入研究的课题.比 如开发医疗健康的应用.运动量监视器等.本文采用ht ...

  5. 银行家算法中安全性检查子算法的实现

    实验内容: 编程实现银行家算法中的安全性检查子算法,要求: (1) 本程序要能描述 n 个并发进程共享 m 类资源,在某一时刻的资源分配状态: n.m 自定,但都不能小于 3: (2) 本程序功能: ...

  6. 温控仪C语言程序,(转载)温控器PID算法的实现(C语言),未实验

    硬件原理:加热电阻为400,电源为市电,固态继电器控制通断,并提取市电的过零信号,单片机采用mega48,继电器通断最小时间为10ms,通断PWM的周期为100个过零信号. 本程序采用绝对式PID算法 ...

  7. 关于近邻保持算法LLE,LPP,NPE等算法的实现---流行学习

    需要注意的是: 1.在基于流行学习的方法中,所谓的M=(I-W)*(I-W)'中的I是单位矩阵.而不是1 2.对于图W,我们将系数按照一列一列的形式放,并且,Sw = Train_Ma*Mg*Trai ...

  8. 粒子群算法(8)---混合粒子群算法的实现

    混合粒子群算法将全局粒子群算法与局部粒子群算法结合,其速度更新采用公式 其中G(k+1)是全局版本的速度更新公式,而L(k+1)是局部版本的速度更新公式,混合粒子群算法采用H(k+1)的公式. 位置更 ...

  9. PHP生成订单号的五种方法:时间拼接随机数 混拼字母 减年份转十六进制 雪花算法 拼接时间戳与随机数

    第一种:年月日时分秒+拼接随机数   危险 稍微体量一大这种肯定有重复 $danhao = date('YmdHis') . str_pad(mt_rand(1, 99999), 5, '0', ST ...

最新文章

  1. E. Turn Off The TV Educational Codeforces Round 29
  2. QTP中对用户自定义环境变量的XML操作的几个函数
  3. NumPy快速入门--复制/视图/深拷贝
  4. 服务器对象错误quot;ASP 0177:80040154quot;Server.CreateObject
  5. 电力装置的继电保护和自动装置设计规范_继电保护装置升级到微机保护装置
  6. ai怎么渐变颜色_你根本想不到AI的混合工具有多神奇!
  7. 简记:我的Scala学习之路
  8. 蓝桥杯省赛2016年Java组B组
  9. wordpress制作主题之菜单
  10. Android团队技术随写、随写
  11. wps如何只让他显示3级标题_wps怎么把标题显示出来
  12. 使用WINPE制作U盘启动
  13. 腾讯云云通信TLS后台API在mac上JAVA DEMO搭建
  14. 田忌赛马 - 动态规划
  15. 安徽师大附中%你赛day9 T2 富 解题报告
  16. jca 实例 java_采用jca分析javacore文件示例
  17. HTML5接入百度地图并搜索定位
  18. CSS 样式属性大全
  19. [地图]常用的地图结构
  20. 2022.1.12C语言小练

热门文章

  1. python去除excel空行_python中如何删除excel的行?
  2. 电容,电阻,二极管,三极管
  3. 百度云盘试用时间本地CE修改
  4. 图像主结构的提取方法
  5. ISAM error: no free disk space故障分析处理
  6. 微信上对你回复,“嗯”和“哦”的人是什么心态?怎么才能处理好这个问题?
  7. restfulApi相关
  8. 数据分析3 - 算法篇
  9. 【渝粤题库】陕西师范大学201961 中外教育管理史 作业(专升本)
  10. 操作系统课程设计--模拟时间片轮转法