雪花算法(Snowflake)是 Twitter 设计用于生成唯一ID的分布式算法。它生成的ID是一个64位的长整型数字,结构如下:
+-------------------------+
| 41 | // 前1位永远为0,固定
| 0 | // 42位时间戳,精确到毫秒,可以使用约69年
| 0 | // 10位机器标识,可以部署在1024个节点上
| 0 | // 12位序列号,每毫秒每个节点可以生成4096个ID
+-------------------------+
雪花算法生成的ID是一个递增的数字,因此可以按照生成顺序进行排序。但是,由于ID是递增的,所以雪花算法不适用于需要随机性的场景。
以下是雪花算法的Java实现:
```java public class SnowflakeIdWorker { // 起始的时间戳 private final static long START_TIMESTAMP = 1609459200000L;
// 每个节点的唯一标识
private final static long MACHINE_ID_BITS = 10L;
private final static long MAX_MACHINE_ID = (1L << MACHINE_ID_BITS) - 1;
// 序列号占用的位数
private final static long SEQUENCE_BITS = 12L;
// 时间戳占用的位数
private final static long TIMESTAMP_BITS = 41L;
// 机器标识向左移12位
private final static long MACHINE_ID_SHIFT = SEQUENCE_BITS + TIMESTAMP_BITS;
// 序列号向左移5位
private final static long SEQUENCE_SHIFT = TIMESTAMP_BITS;
// 时间戳向左移22位
private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + SEQUENCE_BITS;
private long lastTimestamp = -1L; // 上次生成ID的时间戳
private long machineId; // 机器标识
private long sequence = 0L; // 序列号
public SnowflakeIdWorker(long machineId) {
if (machineId > MAX_MACHINE_ID || machineId < 0) {
throw new IllegalArgumentException("Machine ID can't be greater than " + MAX_MACHINE_ID + " or less than 0");
}
this.machineId = machineId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & ((1L << SEQUENCE_BITS) - 1);
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT) |
(machineId << MACHINE_ID_SHIFT) |
sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
} ```
使用雪花算法生成唯一ID的步骤如下:
- 创建一个
SnowflakeIdWorker
实例,传入机器ID。 - 调用
nextId()
方法生成唯一ID。