Snowflake
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。
其核心思想是,生成64位即一个long类型的递增序列Id,保障有序及不重复,具体如下:
- 使用41bit作为毫秒数,
- 10bit作为机器的ID,5个bit是数据中心,5个bit的机器ID
- 12bit作为毫秒内的流水号,意味着每个节点在每毫秒可以产生 4096个ID
- 最后还有一个符号位,永远是0
规则
64位=符号位(1bit)+ 时间戳相对值(41bit)+ 数据标志(5bit)+ 机器标志(5bit)+ 递增序号(12bit)
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
Id位数长度
正数Long类型长度为最多19位,因此结果长度在1到19位之间,最小是0,最大9,223,372,036,854,775,807。
一般为18位,但时间超过一定值后,会变为19位。
消耗完18位所需的时间:110^18 / (3600 24 365 1000 * 2^22) ≈ 7.56年,即时间差超过7.56年,就会达到19位。
比如以2010年1月1日为epoch,则差不多到2017年中就19位了。
关于长度,可以通过数字2进制转10进制的长度比。一个用2进制表示的数字是用10进制表示长度的3.3倍。
正整数n,用10进制表示的长度为:
a=⌊log10n⌋+1a=⌊log10n⌋+1
而用2进制表示为:
b=⌊log2n⌋+1b=⌊log2n⌋+1
所以比值:
c=limn→∞ab=limn→∞⌊log10n⌋⌊log2n⌋=log210≈3.32
假设生成长度为15位,则需要字节长度为53。
根据设备生成15位Id
1 | public class SnowFlakeGenerator { |
用位运算计算n个bit能表示的最大数值
1 | long maxNodeId = (int) (~(-1L << 5)); |
所以上面那行代码中,运行顺序是:1
2-1 左移 5,得结果a
-1 异或 a
二进制运算过程如下:1
2
3
4
5-1 左移 5,得结果a :
11111111 11111111 11111111 11111111 //-1的二进制表示(补码)
11111 11111111 11111111 11111111 11100000 //高位溢出的不要,低位补0
11111111 11111111 11111111 11100000 //结果a
1 | -1 异或 a : |
最终结果是31,二进制00000000 00000000 00000000 00011111转十进制可以这么算:
24+23+22+21+20=16+8+4+2+1=31
-1L ^ (-1L << 5L)结果是31,$2^{5}-1$的结果也是31,所以在代码中,-1L ^ (-1L << 5L)的写法是利用位运算计算出5位能表示的最大正整数是多少
防止溢出
1 | sequence = (sequence + 1) & maxSequence |
这段代码通过位与运算保证计算的结果范围始在0-maxSequence,其实就是取余操作。
用位运算汇总结果
|或运算符,也是一个位运算符。
其含义是:x的第n位和y的第n位,只要有一个是1,则结果的第n位也为1,否则为0。
正因为左移的操作,使四个不同的值移到了SnowFlake理论上相应的位置,然后做位或运算(只要有1结果就是1),就把几段的二进制数合并成一个二进制数。
最后转换成10进制,就是最终生成的id。