- 作者:老汪软件技巧
- 发表时间:2024-09-12 21:01
- 浏览量:
在 Spring Boot 中使用雪花算法(Snowflake)来生成分布式唯一 ID 是一种常见的实践。雪花算法由 Twitter 提出,由于其高效性和分布式环境中的唯一性,广泛应用于各种场景中。
雪花算法
雪花算法生成的 64 位长整型 ID 一般由以下几部分组成:
时间戳:通常占用 41 位,用来存储毫秒级的时间戳。数据中心 ID:通常占用若干位,用来标识数据中心。机器 ID:通常占用若干位,用来标识同一数据中心内的不同机器。序列号:通常占用 12 位,用来记录同一毫秒内产生的不同 ID。实现步骤
引入依赖
在你的 pom.xml 文件中添加必要的依赖,例如常用的依赖没有特别指定,可以使用 Spring Boot 的核心依赖。
编写 Snowflake 算法类
你可以自己实现一个简单版本的雪花算法,也可以使用已有的库。以下是一个简单的 Java 实现示例:
public class SnowflakeIdGenerator {
private final long twepoch = 1288834974657L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long sequenceBits = 12L;
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeIdGenerator(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected long timeGen() {
return System.currentTimeMillis();
}
}
使用 Snowflake 算法
创建一个 Spring Boot 服务,并使用该服务生成唯一 ID:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IdController {
private final SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
@GetMapping("/generate-id")
public long generateId() {
return idGenerator.nextId();
}
}
测试
运行你的 Spring Boot 应用程序,访问 /generate-id 端点,即可获取到一个基于雪花算法生成的唯一 ID。
nextId方法解析详细解释
同步关键字(synchronized)
获取当前时间戳
时钟回拨校验
同一毫秒内的序列号处理
更新最后时间戳
生成唯一 ID
小结
nextId 方法利用时间戳、数据中心 ID、机器 ID 和序列号来生成全局唯一的 ID,通过位移操作将这些元素组合成一个长整型数。该方法确保即使在高并发环境中,生成的 ID 也具有唯一性和顺序性。在实际应用中,这一方法能高效支持分布式系统中的唯一标识需求。
思考题:雪花模型一毫秒内最多生成多少个id
由于序列号占用 12 位,这表示在同一个节点上,同一毫秒可以生成的 ID 数量最多为 (2^{12} = 4096) 个。
因此,如果你的系统有多台机器,每台机器都能在每毫秒生成最多 4096 个唯一 ID,那么总体上你可以通过增加机器数量来扩大每毫秒可以生成的 ID 总量。不过,单台机器在单毫秒内直接生成的 ID 数量上限就是 4096 个。