“我正在参加「掘金·启航计划」”
雪花算法
特点
SnowFlake算法是Twitter开源的分布式ID生成算法。核心思想就是:使用一个64 bit的 long 型的数字作为全局唯一ID。算法中还引入了时间戳,基本上保证了自增特性。
原理
SnowFlake算法生成ID的结果是一个64bit大小的整数,结构如下图:
解析
- 第一个部分:1个bit,无意义,固定为0。二进制中最高位是符号位,1表示负数,0表示正数。ID都是正整数,所以固定为0。
- 第二个部分:41个bit,表示时间戳,精确到毫秒,2^41/(1000*60*60*24*365)=69,大概可以使用 69 年。时间戳带有自增属性。
- 第三个部分:10个bit,表示10位的机器标识,最多支持2^10=1024个节点。此部分也可拆分成5位datacenterId和5位workerId,datacenterId表示机房ID,workerId表示机器ID。
- 第四部分:12个bit,表示序列化,同一毫秒时间戳时,通过这个递增的序列号来区分。即对于同一台机器而言,同一毫秒时间戳下,可以生成 2^12=4096 个不重复 id。
特点
- 由于在Java中64bit的整数是long类型,所以在Java中SnowFlake算法生成的id就是long来存储的。
- 对于每一个雪花算法服务,需要先指定 10 位的机器码,这个根据自身业务进行设定即可。例如机房号+机器号,机器号+服务号,或者是其他可区别标识的 10 位比特位的整数值都行。
优点
- 高并发分布式环境下生成不重复 id,每秒可生成百万个不重复 id。
- 基于时间戳,以及同一时间戳下序列号自增,基本保证 id 有序递增。
- 不依赖第三方库或者中间件。
- 算法简单,在内存中进行,效率高。
缺点
- 依赖服务器时间,服务器时钟回拨时可能会生成重复 id。算法中可通过记录最后一个生成 id 时的时间戳来解决,每次生成 id 之前比较当前服务器时钟是否被回拨,避免生成重复 id。
注意
- 雪花算法每一部分占用的比特位数量并不是固定死的。例如你的业务可能达不到 69 年之久,那么可用减少时间戳占用的位数,雪花算法服务需要部署的节点超过1024 台,那么可将减少的位数补充给机器码用。
- 雪花算法中 41 位比特位不是直接用来存储当前服务器毫秒时间戳的,而是需要当前服务器时间戳减去某一个初始时间戳值,一般可以使用服务上线时间作为初始时间戳值。
- 对于机器码,可根据自身情况做调整,例如机房号,服务器号,业务号,机器 IP 等都是可使用的。对于部署的不同雪花算法服务中,最后计算出来的机器码能区分开来即可。
实现
public class SnowFlake {
/**
* 起始的时间戳(可设置当前时间之前的邻近时间)
*/
private final static long START_STAMP = 1480166465631L;
/**
* 序列号占用的位数
*/
private final static long SEQUENCE_BIT = 12;
/**
* 机器标识占用的位数
*/
private final static long MACHINE_BIT = 5;
/**
* 数据中心占用的位数
*/
private final static long DATA_CENTER_BIT = 5;
/**
* 每一部分的最大值
*/
private final static long MAX_DATA_CENTER_NUM = ~(-1L