分布式自增ID算法---雪花算法(SnowFlake)Java实现

分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种。

算法原理

SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:

 

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

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

    - 41位可以表示个数字,

    - 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 ,减1是因为可表示的数值范围是从0开始算的,而不是1。

    - 也就是说41位可以表示个毫秒的值,转化成单位年则是年

     

    3:10bit-工作机器id,用来记录工作机器id。

    - 可以部署在个节点,包括5位datacenterId和5位workerId

    - 5位(bit)可以表示的最大正整数是,即可以用0、1、2、3、....31这32个数字,来表示不同的datecenterId或workerId

     

    4:12bit-序列号,序列号,用来记录同毫秒内产生的不同id。

    - 12位(bit)可以表示的最大正整数是,即可以用0、1、2、3、....4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号。

     

    由于在Java中64bit的整数是long类型,所以在Java中SnowFlake算法生成的id就是long来存储的

SnowFlake可以保证:

  1. 所有生成的id按时间趋势递增
  2. 整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

Twitter官方给出的算法实现 是用Scala写的,这里不做分析,可自行查看。

Java版算法实现

public class IdWorker{//下面两个每个5位,加起来就是10位的工作机器idprivate long workerId;    //工作idprivate long datacenterId;   //数据id//12位的序列号private long sequence;public IdWorker(long workerId, long datacenterId, long sequence){// sanity check for workerIdif (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0) {throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));}System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);this.workerId = workerId;this.datacenterId = datacenterId;this.sequence = sequence;}//初始时间戳private long twepoch = 1288834974657L;//长度为5位private long workerIdBits = 5L;private long datacenterIdBits = 5L;//最大值private long maxWorkerId = -1L ^ (-1L << workerIdBits);private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);//序列号id长度private long sequenceBits = 12L;//序列号最大值private long sequenceMask = -1L ^ (-1L << sequenceBits);//工作id需要左移的位数,12位private long workerIdShift = sequenceBits;//数据id需要左移位数 12+5=17位private long datacenterIdShift = sequenceBits + workerIdBits;//时间戳需要左移位数 12+5+5=22位private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;//上次时间戳,初始值为负数private long lastTimestamp = -1L;public long getWorkerId(){return workerId;}public long getDatacenterId(){return datacenterId;}public long getTimestamp(){return System.currentTimeMillis();}//下一个ID生成算法public synchronized long nextId() {long timestamp = timeGen();//获取当前时间戳如果小于上次时间戳,则表示时间戳获取出现异常if (timestamp < lastTimestamp) {System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",lastTimestamp - timestamp));}//获取当前时间戳如果等于上次时间戳(同一毫秒内),则在序列号加一;否则序列号赋值为0,从0开始。if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0;}//将上次时间戳值刷新lastTimestamp = timestamp;/*** 返回结果:* (timestamp - twepoch) << timestampLeftShift) 表示将时间戳减去初始时间戳,再左移相应位数* (datacenterId << datacenterIdShift) 表示将数据id左移相应位数* (workerId << workerIdShift) 表示将工作id左移相应位数* | 是按位或运算符,例如:x | y,只有当x,y都为0的时候结果才为0,其它情况结果都为1。* 因为个部分只有相应位上的值有意义,其它位上都是0,所以将各部分的值进行 | 运算就能得到最终拼接好的id*/return ((timestamp - twepoch) << timestampLeftShift) |(datacenterId << datacenterIdShift) |(workerId << workerIdShift) |sequence;}//获取时间戳,并与上次时间戳比较private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}//获取系统时间戳private long timeGen(){return System.currentTimeMillis();}//---------------测试---------------public static void main(String[] args) {IdWorker worker = new IdWorker(1,1,1);for (int i = 0; i < 30; i++) {System.out.println(worker.nextId());}}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/270009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件:给大家推荐一款国产非常好用的效率软件uTools

目录 1、uTools介绍 2、安装下载 3、uTools常用功能介绍 今天给大家推荐一款办公人员必备的效率软件uTools,可以大幅度提升你的生产力&#xff0c;感兴趣的朋友可以下载试一试&#xff0c;相信你一定会爱不释手。 1、uTools介绍 uTools是一款插件化&#xff0c;极简、跨平…

iOS Coding项目片段记录(八)

继续一些小知识点&#xff0c;想起来就贴出来。 监测网络状态1.主动监测监测网络状态是否WIFI (BOOL)isEnableWIFI {return ([[Reachability reachabilityForLocalWiFi] currentReachabilityStatus] ! NotReachable);}是否3G (BOOL)isEnable3G {return ([[Reachability reachab…

数据库知识:SQLServer创建非sa用户笔记

数据库安全是数据库运维非常重要的环节&#xff0c;今天给大家分享SQLServer如何创建非sa用户&#xff0c;并且设置数据库对应的访问权限&#xff0c;希望对大家能有所帮助&#xff01; 1、创建登录名 1.1、创建登录名 安全性→登录名→新建登录名&#xff08;鼠标右键&#xf…

start() 跟 run() 方法的区别和联系

这里还有个知识点是 start() 跟 run() 方法的区别和联系。 直接调用 start() 方法&#xff0c;此时线程处于一个就绪&#xff08;可运行&#xff09;的状态&#xff0c;但是并没有真正的运行。而是得到CPU 的时间片后&#xff0c;开始执行 run() 方法&#xff0c;run() 方法里…

四维偏序 CDQ套CDQ

对CDQ深一步的理解 昨天做了一道CDQ,看了一堆CDQ可做的题,今天又做了一道四维偏序 感觉对CDQ的理解又深了一点,故来写一写现在自己对于CDQ的理解 CDQ其实就是实现了这样的一个问题的转化:\(a_{l} < a_{l1} < ... < a_r > (a_l,a_{l1},...,a_{mid}) \text{都小于} (…

微软电脑管家2.0公测版体验

前言 微软电脑管家2.0公测版本终于发布了&#xff0c;之前给大家分享过微软电脑管家测试版的文章&#xff0c;今天给大家再介绍一下微软电脑管家2.0公测版究竟带来了哪些更新&#xff0c;大家一起来看看吧&#xff01; 安装要求 微软官方公布的安装要求是windows10的1809版本…

布隆过滤器(Bloom Filter)的原理和实现

布隆过滤器使用场景 之前在《数学之美》里面看到过布隆过滤器的介绍。那么什么场景下面需要使用布隆过滤器呢&#xff1f; 看下下面几个问题 字处理软件中&#xff0c;需要检查一个英语单词是否拼写正确在 FBI&#xff0c;一个嫌疑人的名字是否已经在嫌疑名单上在网络爬虫里&a…

硬件知识:RTMP和RTSP传统流媒体协议介绍

今天给大家分享RTMP和RTSP传统流媒体协议介绍&#xff0c;希望对大家能有所帮助&#xff01; 1、RTSP 1.1 RTSP协议介绍 RTSP &#xff08;Real-Time Stream Protocol&#xff09;由Real Networks 和 Netscape共同提出的&#xff0c;基于文本的多媒体播放控制协议。RTSP定义…

常见Java面试题

一、Java基础 1、Arrays.sort实现原理和Collections.sort实现原理 答&#xff1a;Collections.sort方法底层会调用Arrays.sort方法&#xff0c;底层实现都是TimeSort实现的。TimSort算法就是找到已经排好序数据的子序列&#xff0c;然后对剩余部分排序&#xff0c;然后合并起…

电脑知识:台式电脑应该选择品牌和组装,值得收藏

互联网时代的发展&#xff0c;电脑对大家日常办公、游戏、影音娱乐都是常用的设备。今天主要给大家分享一下购买台式电脑应该注重品牌还是组装&#xff0c;相信看完本文对你选购台式电脑提供更多的参考。 1、品牌电脑 品牌电脑就是由大品牌电脑厂商&#xff08;联想、IBM、戴…

Atitit it行业图像处理行业软件行业感到到迷茫的三大原因和解决方案

Atitit it行业图像处理行业软件行业感到到迷茫的三大原因和解决方案 1. 迷茫的原因最大原因是未知1 1.1. 我在哪里&#xff1f;&#xff1f;自己的定位&#xff0c;1 1.2. 正确方向是什么&#xff1f;&#xff1f;1 1.3. 虽然找到方向&#xff0c;但前面一片迷雾&#xff0c;迷…

Docker基础:Docker是什么,为什么这么火

一、Docker是什么&#xff1f; Docker是一个开源的应用容器引擎&#xff0c;它基于go语言开发&#xff0c;并遵从Apache2.0开源协议。使用Docker可以让开发者封装他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任意的 Linux 机器上运行。Docker 的核心思想打…

信息系统 项目十大管理和五大过程

PMBOK五大过程组是什么&#xff1f; PMBOK五大过程组是&#xff1a;启动过程、规划过程、执行过程、监控过程、收尾过程。 各用一句话概括项目管理知识体系五大过程组&#xff1a; 1、启动过程组&#xff1a;作用是设定项目目标&#xff0c;让项目团队有事可做&#xff1b; 2、…

查看端口占用

//进入 c:\WINDOWS\system32\ 目录 cd c:\WINDOWS\system32\ // 键入命令 netstat -ano // 查看指定端口占用情况 netstat -aon|findstr "9050"转载于:https://www.cnblogs.com/lpt1229/p/6408008.html

Docker基础:Docker安装及镜像加速配置

今天给大家分享Centos7以上版本的操作系统下安装Docker。 目录 卸载旧版本docker 安装docker需要的安装包 设置镜像仓库 国内常见镜像仓库 安装docker 启动docker 运行hello-world 卸载docker&#xff08;谨慎操作&#xff09; 确认操作系统版本 #查看系统内核 uname …

高并发场景下,到底先更新缓存还是先更新数据库?

在大型系统中&#xff0c;为了减少数据库压力通常会引入缓存机制&#xff0c;一旦引入缓存又很容易造成缓存和数据库数据不一致&#xff0c;导致用户看到的是旧数据。 为了减少数据不一致的情况&#xff0c;更新缓存和数据库的机制显得尤为重要&#xff0c;接下来带领大家踩踩…

Xamarin组件包 Xamarin.ToolKit

一 简介 Xamarin.ToolKit是个人在使用xamrin.froms开发2年中&#xff0c;因实际项目需要所自定义的组件包。该组件包采用xamarin.froms方式封装&#xff0c;用户可像普通forms控件那样使用xaml语言编写UI代码。目前该组件包的成员主要&#xff1a; 1 TabbedPage.cs&#xff1a…

Docker基础:Docker运行原理笔记

目录 1、Docker底层运行原理 2、Docker执行run命令的流程 3、Docker容器的生命周期

每个工程师都应该了解的:聊聊幂等

现在这个时代大家可能最关心的就是钱了&#xff0c;那么有没有想过你银行转账给你没有一次是转多的&#xff0c;要么失败&#xff0c;要么成功&#xff0c;为什么不能失误一下多转一笔呢&#xff1f;醒醒吧年轻人&#xff0c;别做梦了&#xff0c;做银行的能那么傻x吗&#xff…

《架构之美》阅读笔记四

书中提到了ruby on rails,所以百度了下&#xff0c;介绍如下&#xff1a; 题外话&#xff1a;Ruby on rails 它是一种可以使你开发&#xff0c;部署和维护的WEB应用程序变得简单的框架&#xff0c;以简化web开发为目标&#xff0c;它简洁&#xff0c;易懂&#xff0c;框架里的配…