分布式id
- 雪花算法能够生成一个64位long类型数据,适合做分布式系统的全局标识符,或者分库分表中,同类型数据表的主键
原理探究
- 雪花算法:以一台服务器为对象,在一毫秒时间内,生成一个自增的long数据
- 特点:雪花算法生成的id具有唯一性,和实时性
下面,就来研究一下,雪花id是如何保证全局唯一的
组成
划重点:一位符号位,41位时间毫秒数,10位机器id,12位同毫秒自增序号,共64位
由此,我们可以分析得出以下结论:
- 时间戳位于高位,且时间戳随时间递增,所以,雪花id随时间递增
- 10位机器id,一共可以为2^10=1024台服务器生成id
- 12位序列号,即在1毫秒内,可以生成2^12=4096个id,换句话说,就是雪花id最高支持409 万的每秒并发量
- 雪花id是否会重复,取决于时间戳是否重复,也就是说,当服务器调回过去的时间时,就会导致雪花id不再唯一
生成过程
/**
* 雪花算法生成id
*/
public class SnowFlakeClient {
/**
* 起始时间戳
*/
private static final long START_TIMESTAMP = 1704038400L; //2024-01-01 00:00:00
/**
* 各组成部分占用的位数
* */
/**
* 时间戳
*/
private static final long TIMESTAMP_BIT = 41;
/**
* 机器id
*/
private static final long MACHINE_BIT = 10;
/**
* 序列号
*/
private static final long SEQUENCE_BIT = 12;
// 每一部分的最大值
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
private static final long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
// 每一部分向左的位移
private static final long MACHINE_LEFT = SEQUENCE_BIT;
private static final long TIMESTAMP_LEFT = SEQUENCE_BIT + MACHINE_BIT;
/**
* 上一次生成id的时间戳(不断改变)
*/
private static long lastTimeStamp = -1L;
/**
* 递增序列号
*/
private static long sequence = 0L;
/**
* 生成雪花id
*/
public static long nextId() {
//1.获取当前时间戳
long now = System.currentTimeMillis();
//2.判断服务器是否时钟回拨
if (now < lastTimeStamp) {
throw new RuntimeException("服务器时钟回拨,可能会导致id不唯一");
}
//3.判断是否在同一毫秒
if (now == lastTimeStamp) {
//3.1同一毫秒内,就让序列号递增,注意不要超出最大范围
sequence = (sequence + 1) & MAX_SEQUENCE;//做与运算就能去掉超出最高位的数字
if (sequence == 0L) {
//3.1.1序列号已经用完了,本毫秒内不再生成新id
now = System.currentTimeMillis();
while (now <= lastTimeStamp) {
now = System.currentTimeMillis();
}
}
} else {
//不在同一个毫秒,重置序列号
sequence = 0L;
}
//更新时间戳
lastTimeStamp = now;
//4.组合成id:使用移位,以及或运算
long id = ((now - START_TIMESTAMP) << TIMESTAMP_LEFT) | (IdConfig.machineId << MACHINE_LEFT) | sequence;
return id;
}
}
测试:
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Long.toBinaryString(SnowFlakeClient.nextId()));
}
}
}
结果:
110001110111110101001000111111101111111100000000000000000000000
110001110111110101001000111111110001001010000000000000000000000
110001110111110101001000111111110001001010000000000000000000001
110001110111110101001000111111110001001010000000000000000000010
110001110111110101001000111111110001001010000000000000000000011
110001110111110101001000111111110001001010000000000000000000100
110001110111110101001000111111110001001010000000000000000000101
110001110111110101001000111111110001001010000000000000000000110
110001110111110101001000111111110001001010000000000000000000111
110001110111110101001000111111110001001010000000000000000001000
110001110111110101001000111111110001001010000000000000000001001
110001110111110101001000111111110001001010000000000000000001010
110001110111110101001000111111110001001100000000000000000000000
110001110111110101001000111111110001001100000000000000000000001
110001110111110101001000111111110001001100000000000000000000010
110001110111110101001000111111110001001100000000000000000000011
110001110111110101001000111111110001001100000000000000000000100
110001110111110101001000111111110001001100000000000000000000101
110001110111110101001000111111110001001100000000000000000000110
110001110111110101001000111111110001001100000000000000000000111
110001110111110101001000111111110001001100000000000000000001000
110001110111110101001000111111110001001100000000000000000001001
110001110111110101001000111111110001001100000000000000000001010
110001110111110101001000111111110001001100000000000000000001011
110001110111110101001000111111110001001100000000000000000001100
110001110111110101001000111111110001001100000000000000000001101
110001110111110101001000111111110001001100000000000000000001110
在这里插入代码片