龙空技术网

「Idworker」分布式自增长ID详解及添加自有业务

java狒狒 1237

前言:

现时我们对“java自增长”大约比较看重,兄弟们都想要学习一些“java自增长”的相关知识。那么小编同时在网络上网罗了一些对于“java自增长””的相关文章,希望兄弟们能喜欢,朋友们快快来了解一下吧!

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

这里我首先来把代码展示一下

1:类的描述信息

/*** <p>名称:IdWorker.java</p>* <p>描述:分布式自增长ID</p>* <pre>* Twitter的 Snowflake JAVA实现方案* </pre>* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),* 然后12位当前毫秒内的计数(用于控制一毫秒内的高并发),加起来刚好64位,为一个Long型。(这里我在12位的最后一位增加了奇偶性,下面会详解)* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。* <p>* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))* @author java baboon*/

下面是IdWorker类中的属性变量

// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)private final static long twepoch = 1516489628123L;//对应时间2018-01-21 7:7:8.123// 机器标识位数private final static long workerIdBits = 5L;// 数据中心标识位数private final static long datacenterIdBits = 5L;// 机器ID最大值private final static long maxWorkerId = ~ (-1L << workerIdBits);//二进制5位最大值:11111=十进制31// 数据中心ID最大值private final static long maxDatacenterId = ~(-1L << datacenterIdBits);//二进制5位最大值:11111// 毫秒内自增位:我创建的是11位,连上奇偶性位数12位private final static long sequenceBits = 11L;//数字的奇偶性private final static long odevityBits=1;//添加自己的业务是数据具有奇偶性,在使用该id生成器是发现如果不是高并发的生成id,生成的每个//毫秒内自增向左移1位private final static long sequenceShift=odevityBits;// 机器ID偏左移12位private final static long workerIdShift = odevityBits + sequenceBits;// 数据中心ID左移17位private final static long datacenterIdShift = odevityBits + sequenceBits + workerIdBits;// 时间毫秒左移22位private final static long timestampLeftShift =odevityBits + sequenceBits + workerIdBits + datacenterIdBits;//序列号最大值11位:11111111111=2047private final static long sequenceMask = ~ (-1L << sequenceBits);//2047/* 上次生产id时间戳 */private static long lastTimestamp = -1L;// 0,并发控制private long sequence = 0L;private long odevity=0;private final long workerId;// 数据标识id部分private final long datacenterId;

截图:

构造函数

构造函数中主要判断的是:workId和datacenter不能大于他们限定的最大值31

生成id的方法:

下面来详解一下:

从左开始:

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

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

41位可以表示241−1个数字,

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

也就是说41位可以表示241−1个毫秒的值,转化成单位年则是(241−1)/(1000∗60∗60∗24∗365)=69年

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

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

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

最后12位:序列号,用来记录同毫秒内产生的不同id,最后12位之前都比较好理解,就是这个最后的12位,猛一看有点蒙,其实这12位就是来防止高并发的,可以做到1毫秒内产生4095个数字,已经做的非常精细了

分布式生成ID的作用:特别强调第二条

SnowFlake可以保证:

所有生成的id按时间趋势递增

整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

下面来说一下生成id里面最主要的代码:

// ID偏移组合生成最终的ID,并返回IDlong nextId = ((timestamp - twepoch) << timestampLeftShift)| (datacenterId << datacenterIdShift)| (workerId << workerIdShift) | sequence<<sequenceShift | odevity;

timestamp - twepoch:当前时间减去自己设置的时间值,twepoch:只能是当前时间值之前的一个值比如当前是2018-01-21 07:07:07,那么twepoch只能是这之前的时间,当然都转化为timestamp类型的,然后把得到的值向左移动22位,这里说明一下为什么要移动22位:因为这22位要放workID和dataCenterID和sequenceShift和odevity,控制机器id,数据id,序列号和奇偶性,数字的位置

datacenterId << datacenterIdShift:同理向左移动17位给别的数字腾出来位置,下面一次同理,本来sequence是12位,但是由于,在实际应用中,并不会出现在一毫秒内出现很高的并发,造成sequence一直是0,所以生成的id一直是偶数,为了让生成的id奇偶交替出现,我专门添加了一个odevity的位,来控制奇偶性,我想到这里,大家应该知道专门添加自己的业务逻辑了吧,其实就是专门向左移动

OK,有什么问题,留言讨论,大家共同进步,谢谢

标签: #java自增长