理解分布式id生成算法--雪花算法(SnowFlake)

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

注:

1B就是1个字节。
Byte、KB、B、MB、GB之间的关系是:
Bit——比特 ; B ——字节;KB——千字节;MB——兆字节;GB——吉字节;TB——太字节
1bit=0.125b ;1B=8 Bit   ;1KB=1024B      1MB=1024KB;1GB=1024MB;1TB=1024GB

 

1位,不用。二进制中最高位为1的都是负数,但是我们生成的ID一般都使用整数,所以这个最高位固定是0.

41位,用来记录时间戳(毫秒)

            41位可以表示正整数(计算机中整数包含0),可以表示的数值范围是:0至$2^{41}-1$,

            减1是因为可表示的的数值范围是从0开始算的,而不是1.

             也就是说41位可以表示$2^{41}-1$个毫秒的值,转化成单位年则是$2^({41}-1)/(1000*60*60*24*365)=69$年

10位,用来记录工作机器ID。

         可以部署在$2^{10}=1024$个字节。包括5位datacenterId和5位workerId。

          5位(bit)可以表示的最大正整数是$2^{5}-1=31$,即可以用0,1,2,3....31这32个数字,来表示不同的datacenterId 

          或者workerId.

12位,序列号,用来记录同毫秒内产生的不同Id。

        12位(bit)可以表示的最大整数是$2^{12}-1=4095$,即可以用0、1、2、3....4094这4095个数字,来表示同一机器

         同一时间戳(毫秒)内产生的4095个ID序号。

由于在java中64bit的整数是long类型,所以在java中SnowFlake算法生产的ID就是longKauai存储的,

 

SnowFlake可以保证:

所有生成ID按时间趋势递增。

整个分布式系统内不会产生重复ID(因为datacenterID和wokerID来做区分)

 

 

java代码工具类:

 

package suanfa;

/**
* ### 雪花算法:
SnowFlake算法用来生成64位的ID,刚好可以用long整型存储,能够用于分布式系统中生产唯一的ID, 并且生成的ID有大致的顺序。 在这次实现中,生成的64位ID可以分成5个部分:

`0 - 41位时间戳 - 5位数据中心标识 - 5位机器标识 - 12位序列号`

````java
* twitter的snowflake算法 -- java实现
*
* @author beyond
* @date 2016/11/26
*/
public class SnowFlake {

/**
* 起始的时间戳
*/
private final static long START_STMP = 1480166465631L;

/**
* 每一部分占用的位数
*/
private final static long SEQUENCE_BIT = 12; //序列号占用的位数
private final static long MACHINE_BIT = 5; //机器标识占用的位数
private final static long DATACENTER_BIT = 5;//数据中心占用的位数

/**
* 每一部分的最大值
*/
//最大支持数据中心节点数0~31,一共32个
private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
//最大支持机器节点数0~31,一共32个
private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
//序列号0~12,一共12个
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

/**
* 每一部分向左的位移
*/
//机器节点左移12位
private final static long MACHINE_LEFT = SEQUENCE_BIT;
//数据中心节点左移17位
private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
//时间毫秒数左移22位
private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

private long datacenterId; //数据中心
private long machineId; //机器标识
private long sequence = 0L; //序列号
private long lastStmp = -1L;//上一次时间戳 //最大为4095

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;
}

/**
* 产生下一个ID
*
* @return
*/
public synchronized long nextId() {
long currStmp = getNewstmp();
if (currStmp < lastStmp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}

if (currStmp == lastStmp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currStmp = getNextMill();
}
} else {
//不同毫秒内,序列号置为0
sequence = 0L;
}

lastStmp = currStmp;

return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
| datacenterId << DATACENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence; //序列号部分
}

private long getNextMill() {
long mill = getNewstmp();
while (mill <= lastStmp) {
mill = getNewstmp();
}
return mill;
}

private long getNewstmp() {
return System.currentTimeMillis();
}

public static void main(String[] args) {
//数据中心id,机器标识id
SnowFlake snowFlake = new SnowFlake(2, 3);
System.out.println(snowFlake.nextId());

}

}

 

转载于:https://www.cnblogs.com/javaDB2019/p/10935854.html

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

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

相关文章

注解 @PostConstruct 与 @PreDestroy 详解及实例

简介 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Java EE5 引入了PostConstruct和PreDestroy这两个作用于Servlet生命周期的注解&#xff0c;实现Bean初始化之前和销毁之前的自定义操…

PHP 安装xdebug

xdebug官网: https://xdebug.org 安装步骤如下: 使用 phpinfo() 打印出PHP相关信息, 全选, 复制 打开 xdebug 网站: https://xdebug.org/wizard.php 在图中输入框中粘贴你复制的信息, 点击 Analyse my phpinfo() output 在结果中点击下载, 然后按照它提示的步骤进行操作即可…

分布式消息中间件 : Rocketmq

简述 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 分布式消息中间件&#xff0c;主要是实现分布式系统中解耦、异步消息、流量销锋、日志处理等场景。生产中用的最多的消息队…

消息中间件:RocketMQ 介绍(特性、术语、原理、优缺点、消息顺序、消息重复)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 消息中间件的作用 1. 应用解耦 2. 异步处理 比如用户注册场景&#xff0c;注册主流程完成以后&#xff0c;需要调用邮件系统发送邮件…

使用 Intellij Idea 打包 java 工程为可执行 jar 包

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 其实还有个简单多了方法&#xff0c;见&#xff1a; 超简单方法&#xff1a; Intellij Idea 把 java 工程打成可运行的 jar 步骤&#x…

QuickStart系列:docker部署之Gitlab本地代码仓库

gitlab是可以在本地搭建的使用git作为源代码管理的仓库。 运行环境&#xff1a; win10vmware14docker7docker 1. 使用命令拉取镜像&#xff08;非必须&#xff0c;耗时比较久&#xff0c;这里以ce为准&#xff0c;ce是社区版&#xff0c;ee是企业版&#xff09;&#xff1a; do…

超简单方法: Intellij Idea 把 java 工程打成可运行的 jar

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 找到 Intellij Idea 最下面的 Terminal 选项&#xff0c;并点击进入该界面。 2. 在光标位置输入命令&#xff1a;mvn clean 。清理…

kafka集群搭建(消息)

1、Kafka使用背景在我们大量使用分布式数据库、分布式计算集群的时候&#xff0c;是否会遇到这样的一些问题&#xff1a;我们想分析下用户行为&#xff08;pageviews&#xff09;&#xff0c;以便我们设计出更好的广告位我想对用户的搜索关键词进行统计&#xff0c;分析出当前的…

[转]在Windows 下使用OpenCL

目前&#xff0c;NVIDIA和AMD的Windows driver均有支援OpenCL&#xff08;NVIDIA的正式版driver是从195.62版开始&#xff0c;而AMD则是从9.11版开始&#xff09;。NVIDIA的正式版driver中包含OpenCL.dll&#xff0c;因此可以直接使用。AMD到目前为止&#xff0c;则仍需要安装其…

docker 之 Dockerfile 实践

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 上一篇介绍了Dockerfile中使用的指令&#xff0c;现在开始进行指令实践 先查看下本地的镜像&#xff0c;选一个作为base image&#xf…

tomcat启动后命令行日志中文乱码

这是日志的编码设置和窗体的编码格式不一致。 将 conf\logging.properties 文件中的 UTF-8 改成 GBK 重启tomcat &#xff08;右键cmd标题栏部分&#xff0c;可以查看cmd属性&#xff09; 转载于:https://www.cnblogs.com/Echiops/p/10974587.html

Coursera机器学习笔记(一) - 监督学习vs无监督学习

转载 http://daniellaah.github.io/2016/Machine-Learning-Andrew-Ng-My-Notes-Week-1-Introduction.html 一. 监督学习 什么是监督学习? 我们来看看维基百科中给出的定义: 监督式学习&#xff08;英语&#xff1a;Supervised learning&#xff09;&#xff0c;是一个机器学习…

基于OpenCL的mean filter性能

1.对于一个标准的3*3 均值滤波&#xff0c;kernel代码如下&#xff1a; 使用buffer/image缓冲对象 __kernel void filter(__global uchar4* inputImage, __global uchar4* outputImage, uint N) {int x get_global_id(0);int y get_global_id(1);int width get_global_size(…

Docker 实战:编写 Dockerfile

一、编译镜像 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 编译镜像 Dockerfile类似于Makfile&#xff0c;用户使用docker build就可以编译镜像&#xff0c;使用该命令可以设置编译…

dubbo-环境搭建,实现一个简单地dubbo实例(附github地址)

一、建立maven模块和provider、consumer、service子模块&#xff0c;其中service是开发接口的模块 建立一个maven模块&#xff0c;不选择样板&#xff0c;直接next知道完成&#xff0c;建立三个子模块,建立完后发现各个模块的java目录不是源目录 右键——>make Directory as…

AMD 5XXX 系列显卡的 peak bandwidth计算

在ATI Stream Computing Programming Guide中&#xff0c;例举了AMD 5系列显卡的参数信息。 我比较关注其中Peak bandwidths的计算&#xff0c;以便在opencl程序测试bandwidth利用率。 下面&#xff0c;我以5870为例&#xff0c;探讨一下如何计算得到这些结果&#xff1a; L1 c…

OpenCL memory object 之 Global memory (1)

这篇日志是学习AMD OpenCL文档时候的总结。 OpenCL用memory object在host和device之间传输数据&#xff0c;memory object由runtime&#xff08;运行库&#xff0c;driver的一部分&#xff09;来管理。 OpenCL中的内存对象包括buffer以及image&#xff0c;buffer是一维数据元素…

OpenCL memory object 之 Global memory (2)

当我们用clCreateBuffer, clCreateImage创建OpenCL memory object时候&#xff0c;我们需要输入一个flag参数&#xff0c;这个参数决定memory object的位置。 cl_mem clCreateBuffer (cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errc…

数据结构进阶篇-跳表

大家想必都知道&#xff0c;数组和链表的搜索操作的时间复杂度都是O(N)的&#xff0c;在数据量大的时候是非常耗时的。对于数组来说&#xff0c;我们可以先排序&#xff0c;然后使用二分搜索&#xff0c;就能够将时间复杂度降低到O(logN)&#xff0c;但是有序数组的插入是一个O…

查看本机ssh公钥,生成公钥

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 查看ssh公钥方法&#xff1a; 1.通过命令窗口&#xff1a;打开你的git bash 窗口&#xff0c;进入.ssh目录&#xff1a;cd ~/.ssh&…