SnowFlake 算法:是 Twitter 开源的分布式 id 生成算法。
核心思想:使用一个 64 bit 的 long 型的数字作为全局唯一 id。
首先了解一下雪花ID的结构:从网上盗用一张;

针对上面各个部分做简单说明:

  1. 1bit:不用;因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0。

  2. 41bit-时间戳,用来记录时间戳,毫秒级。

  • 41位可以表示241-1个数字,
  • 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 241- 1;减1是因为可表示的数值范围是从0开始算的,而不是1。
  • 也就是说41位可以表示241-1个毫秒的值,转化成单位年则是(241-1) / (1000 * 60 * 60 * 24 * 365)=69年
  1. 10bit-工作机器id,用来记录工作机器id。代表的是这个服务最多可以部署在 210 台机器上,也就是 1024 台机器。
  • 可以部署在个节点,包括5位datacenterId和5位workerId;
  • 10 bit 里 5 个 bit 代表机房 id,5 个 bit 代表机器 id。意思就是最多代表 2 5 个机房(32 个机房),每个机房里可以代表 2 5 个机器(32 台机器),也可以根据自己公司的实际情况确定
  • 5位(bit)可以表示的最大正整数是,即可以用0、1、2、3、…31这32个数字,来表示不同的datecenterId或workerId;
  1. 12bit-序列号,序列号,用来记录同毫秒内产生的不同id。
  • 12位(bit)可以表示的最大正整数是212 - 1 ,即可以用0、1、2、3、…4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号。

  • 对于分布式中雪花ID的应用理解:
    SnowFlake算法生成的ID大致上是按照时间递增的,用在分布式系统中时,需要注意数据中心标识和机器标识必须唯一,这样就能保证每个节点生成的ID都是唯一的。或许我们不一定都需要像上面那样使用5位作为数据中心标识,5位作为机器标识,可以根据我们业务的需要,灵活分配节点部分,如:若不需要数据中心,完全可以使用全部10位作为机器标识;若数据中心不多,也可以只使用3位作为数据中心,7位作为机器标识
    snowflake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。据说:snowflake每秒能够产生26万个ID。

综上,简单举例说明一下:

0 - 0001100101 0001010111 1101000100 1010111000 0 - 10001 - 11001 - 000000000000

第一个部分,是 1 个 bit:0,这个是无意义的。
第二个部分是 41 个 bit:表示的是时间戳。
第三个部分是 5 个 bit:表示的是机房 id,10001。
第四个部分是 5 个 bit:表示的是机器 id,11001。
第五个部分是 12 个 bit:表示的序号,就是某个机房某台机器上这一毫秒内同时生成的 id 的序号,000000000000。

源码实现

package com.qxy.utils;/*** @author wx* */
public final class SnowFlake {// 起始的时间戳private final static long START_STMP = 1577808000000L; //2020-01-01// 每一部分占用的位数,就三个private final static long SEQUENCE_BIT = 12; //序列号占用的位数private final static long MACHINE_BIT = 5; //机器标识占用的位数private final static long DATACENTER_BIT = 5; //数据中心占用的位数// 每一部分最大值private final static long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT);private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);// 每一部分向左的位移private final static long MACHINE_LEFT = SEQUENCE_BIT;private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;private long datacenterId; //数据中心private long machineId; //机器标识private long sequence = 0L; //序列号private long lastStmp = -1L; //上一次时间戳public SnowFlake(long datacenterId, long machineId) {if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");}if (machineId > MAX_MACHINE_NUM || machineId < 0) {throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");}this.datacenterId = datacenterId;this.machineId = machineId;}//产生下一个IDpublic synchronized long nextId() {long currStmp = timeGen();if (currStmp < lastStmp) {throw new RuntimeException("Clock moved backwards.  Refusing to generate id");}if (currStmp == lastStmp) {//if条件里表示当前调用和上一次调用落在了相同毫秒内,只能通过第三部分,序列号自增来判断为唯一,所以+1.sequence = (sequence + 1) & MAX_SEQUENCE;//同一毫秒的序列数已经达到最大,只能等待下一个毫秒if (sequence == 0L) {currStmp = getNextMill();}} else {//不同毫秒内,序列号置为0//执行到这个分支的前提是currTimestamp > lastTimestamp,说明本次调用跟上次调用对比,已经不再同一个毫秒内了,这个时候序号可以重新回置0了。sequence = 0L;}lastStmp = currStmp;//就是用相对毫秒数、机器ID和自增序号拼接return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分| datacenterId << DATACENTER_LEFT       //数据中心部分| machineId << MACHINE_LEFT             //机器标识部分| sequence;                             //序列号部分}private long getNextMill() {long mill = timeGen();while (mill <= lastStmp) {mill = timeGen();}return mill;}private long timeGen() {return System.currentTimeMillis();}public static void main(String[] args) {SnowFlake snowFlake = new SnowFlake(2, 3);for (int i =0; i < 1000; i ++) {System.out.println(snowFlake.nextId());}}}

总结:
SnowFlake 算法系统:首先从配置文件中读取自己所在的机房和机器,比如机房 id = 17,机器 id = 12。接着 SnowFlake 算法系统接收到这个请求之后,用二进制位运算的方式生成一个 64 bit 的 long 型 id,64 个 bit 中的第一个 bit 是无意义的。
接着 41 个 bit,就可以用当前时间戳(单位到毫秒),然后接着 5 个 bit 设置上这个机房 id,还有 5 个 bit 设置上机器 id。
最后再判断一下,当前这台机房的这台机器上这一毫秒内,这是第几个请求,给这次生成 id 的请求累加一个序号,作为最后的 12 个 bit。

Java系列之雪花算法和原理相关推荐

  1. java如何用雪花算法批量生成唯一编码(保证位数不过长)?

    最近有点忙,现在稍微闲一些,就想写写最近遇到的一些业务. 业务:一些商户.市场.档口等主体需要有唯一编码. 思路:一些前缀+雪花算法,此时位数过多,再转成六十四进制缩短位数即可.同时为了实现批量生成唯 ...

  2. 分布式--雪花算法--使用/原理/实例

    原文网址:分布式--雪花算法--使用/原理/实例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍分布式中的雪花算法.包括:用法.原理. 雪花算法用于生成全局的唯一ID. 使用时的注意事项 需要 ...

  3. Java工具类--雪花算法生成全局唯一ID

    import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.NetworkI ...

  4. 机器学习系列------1. GBDT算法的原理

    GBDT算法是一种监督学习算法.监督学习算法需要解决如下两个问题: 1.损失函数尽可能的小,这样使得目标函数能够尽可能的符合样本 2.正则化函数对训练结果进行惩罚,避免过拟合,这样在预测的时候才能够准 ...

  5. 入门电机系列之6PID 算法的原理与应用

    入门电机系列,基于STM32硬件 本文章学习借鉴于野火团队资料,以表感谢.官网http://products.embedfire.com/ 入门电机系列之6PID 算法的原理与应用. 提示:写完文章后 ...

  6. 雪花算法的原理和实现

    雪花算法SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法.其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id.在分布式系统中的应用十分广泛,且I ...

  7. 分布式主键解决方案----Twitter 雪花算法的原理(Java 版)

    SnowFlake 雪花算法 对于分布式系统环境,主键ID的设计很关键,什么自增intID那些是绝对不用的,比较早的时候,大部分系统都用UUID/GUID来作为主键,优点是方便又能解决问题,缺点是插入 ...

  8. 帮我用Java技术实现雪花算法

    雪花算法是一种生成唯一ID的算法,常用于生成数据库主键.分布式系统中的ID等. 以下是Java代码示例: ``` public class SnowflakeIdWorker { // 起始时间戳(毫 ...

  9. java雪花_基于java实现的雪花算法

    一.关于雪花 雪花(snowflake)在自然界中,是极具独特美丽,又变幻莫测的东西:雪花属于六方晶系,它具有四个结晶轴,其中三个辅轴在一个基面上,互相以60度的角度相交,第四轴(主晶轴)与三个辅轴所 ...

最新文章

  1. 任务调度器leetcode621
  2. 后现代婚礼机器人显神通_机器人显神通
  3. 计算机二级mysql模拟_2017年计算机二级MySQL考前模拟练习
  4. Android使用百度翻译api
  5. 对超级计算机的认识有关论文,计算机科与技术专业的认识与思考.docx
  6. 远程服务器返回错误 (411) 所需的长度。
  7. Http Status Code (http 状态号)
  8. plc编程软件通过计算机,英威腾PLC编程软件(Auto Station)
  9. Python 刷题笔记:背包问题
  10. 电脑桌面计算机图标下不显示文字,电脑桌面图标下面的文字有时会突然不见,然后 – 手机爱问...
  11. 数据分析入门系列教程-SVM实战
  12. Running pipenv gives TypeError: 'module' object is not callable
  13. java语言不用pow函数求x的n次方_X的N次方求解——pow(x,n)实现
  14. python之旅【第二篇】
  15. 疫情信息填表-----auto.js 2.0版
  16. 【组合数学】卡特兰数 / 大施罗德数 相关
  17. AS608光学指纹模组编程和应用详解
  18. centos linux 安装jq,在centos中安装jq时遇到问题
  19. 基于移动应用的学习进阶
  20. 《计算机系统应用》期刊投稿经验

热门文章

  1. Dojo1.6 中的事件处理
  2. 【Kubernetes】浅析基本概念和原理
  3. Redis面试常问3 如何实现分布式锁 记住Redis的原子性
  4. 区块链入门与去中心化应用实战 之一 第2章 区块链技术的核心概念和原理
  5. 学神python笔记
  6. 网页截图和svg模版动态生成图片Java实现
  7. mysql 按照条件计数_灵活的CASE...WHEN:SQL同时按条件计数按条件加和
  8. 面试系列-JVM性能优化相关内容
  9. java类型转换_Java类型转换
  10. go中defer的一个隐藏功能