Java系列之雪花算法和原理
SnowFlake 算法:是 Twitter 开源的分布式 id 生成算法。
核心思想:使用一个 64 bit 的 long 型的数字作为全局唯一 id。
首先了解一下雪花ID的结构:从网上盗用一张;
针对上面各个部分做简单说明:
1bit
:不用;因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0。41bit-时间戳
,用来记录时间戳,毫秒级。
- 41位可以表示241-1个数字,
- 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 241- 1;减1是因为可表示的数值范围是从0开始算的,而不是1。
- 也就是说41位可以表示241-1个毫秒的值,转化成单位年则是(241-1) / (1000 * 60 * 60 * 24 * 365)=69年
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;
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系列之雪花算法和原理相关推荐
- java如何用雪花算法批量生成唯一编码(保证位数不过长)?
最近有点忙,现在稍微闲一些,就想写写最近遇到的一些业务. 业务:一些商户.市场.档口等主体需要有唯一编码. 思路:一些前缀+雪花算法,此时位数过多,再转成六十四进制缩短位数即可.同时为了实现批量生成唯 ...
- 分布式--雪花算法--使用/原理/实例
原文网址:分布式--雪花算法--使用/原理/实例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍分布式中的雪花算法.包括:用法.原理. 雪花算法用于生成全局的唯一ID. 使用时的注意事项 需要 ...
- Java工具类--雪花算法生成全局唯一ID
import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.NetworkI ...
- 机器学习系列------1. GBDT算法的原理
GBDT算法是一种监督学习算法.监督学习算法需要解决如下两个问题: 1.损失函数尽可能的小,这样使得目标函数能够尽可能的符合样本 2.正则化函数对训练结果进行惩罚,避免过拟合,这样在预测的时候才能够准 ...
- 入门电机系列之6PID 算法的原理与应用
入门电机系列,基于STM32硬件 本文章学习借鉴于野火团队资料,以表感谢.官网http://products.embedfire.com/ 入门电机系列之6PID 算法的原理与应用. 提示:写完文章后 ...
- 雪花算法的原理和实现
雪花算法SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法.其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id.在分布式系统中的应用十分广泛,且I ...
- 分布式主键解决方案----Twitter 雪花算法的原理(Java 版)
SnowFlake 雪花算法 对于分布式系统环境,主键ID的设计很关键,什么自增intID那些是绝对不用的,比较早的时候,大部分系统都用UUID/GUID来作为主键,优点是方便又能解决问题,缺点是插入 ...
- 帮我用Java技术实现雪花算法
雪花算法是一种生成唯一ID的算法,常用于生成数据库主键.分布式系统中的ID等. 以下是Java代码示例: ``` public class SnowflakeIdWorker { // 起始时间戳(毫 ...
- java雪花_基于java实现的雪花算法
一.关于雪花 雪花(snowflake)在自然界中,是极具独特美丽,又变幻莫测的东西:雪花属于六方晶系,它具有四个结晶轴,其中三个辅轴在一个基面上,互相以60度的角度相交,第四轴(主晶轴)与三个辅轴所 ...
最新文章
- 任务调度器leetcode621
- 后现代婚礼机器人显神通_机器人显神通
- 计算机二级mysql模拟_2017年计算机二级MySQL考前模拟练习
- Android使用百度翻译api
- 对超级计算机的认识有关论文,计算机科与技术专业的认识与思考.docx
- 远程服务器返回错误 (411) 所需的长度。
- Http Status Code (http 状态号)
- plc编程软件通过计算机,英威腾PLC编程软件(Auto Station)
- Python 刷题笔记:背包问题
- 电脑桌面计算机图标下不显示文字,电脑桌面图标下面的文字有时会突然不见,然后 – 手机爱问...
- 数据分析入门系列教程-SVM实战
- Running pipenv gives TypeError: 'module' object is not callable
- java语言不用pow函数求x的n次方_X的N次方求解——pow(x,n)实现
- python之旅【第二篇】
- 疫情信息填表-----auto.js 2.0版
- 【组合数学】卡特兰数 / 大施罗德数 相关
- AS608光学指纹模组编程和应用详解
- centos linux 安装jq,在centos中安装jq时遇到问题
- 基于移动应用的学习进阶
- 《计算机系统应用》期刊投稿经验