如果在面试中被问及分布式唯一标识,却没有答道雪花算法,那么就有点说不过去了.
关于分布式唯一标识中的雪花算法,网络上的介绍很多,它只是一个算法,可以用Python,Java等不同的语言实现它.即便是同一个语言,它的实现也有不同.
美团(Leaf)
百度(uid-generator)
这两个也是业界比较知名的实现雪花算法的工具.
然而还有一个工具类,它就是
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.2</version>
</dependency>
在它的内部也实现和提供了雪花算法,在这里,我们就拿它作为讲解雪花算法的案例.
cn.hutool.core.lang.Snowflake
最核心的方法就是下面这个
public synchronized long nextId() {
// 获取当前时间戳
long timestamp = genTime();
// lastTimestamp表示你的程序在最后一次获取分布式唯一标识的时间戳(ms)
// 一台机器正常情况下,timestamp 是要大于 lastTimestamp的.如果timestamp < lastTimestamp表明服务器的时间有问题,存在时钟后退.
if (timestamp < lastTimestamp) {
// 容忍2秒内的时钟后退
if(lastTimestamp - timestamp < 2000){
timestamp = lastTimestamp;
} else{
// 如果服务器时间有问题(时钟后退) 报错。
throw new IllegalStateException(StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));
}
}
if (timestamp == lastTimestamp) {
// 相同毫秒内,序列号自增
sequence = (sequence + 1) & sequenceMask;
// 同一毫秒的序列数已经达到最大
if (sequence == 0) {
// 循环等待下一个时间
timestamp = tilNextMillis(lastTimestamp);
}
} else {// timestamp > lastTimestamp
// 不同毫秒内, 序列号置为0
sequence = 0L;
}
lastTimestamp = timestamp;
// 通过按位或将各个部分拼接起来
return ((timestamp - twepoch) << timestampLeftShift) // 时间戳部分
| (dataCenterId << dataCenterIdShift) // 数据中心部分
| (workerId << workerIdShift) // 机器标识部分
| sequence; // 序列号部分
}