在分布式系统中,生成唯一且高效的随机 ID 是一个非常常见且重要的需求。例如,订单号、用户 ID、日志跟踪 ID 等,都需要唯一标识。尤其在高并发场景下,随机 ID 生成服务需要具备极高的性能和稳定性,以支撑业务的顺利运行。
本文将详细介绍如何在 Java 中构建一个支持 20 万 QPS 的高并发随机 ID 生成服务,包含设计思路、实现方案及优化方法。
在开始实现之前,我们需要明确以下几点:
在实际中,常见的随机 ID 生成方案如下:
在高并发场景下,Snowflake 是一种非常优秀的分布式 ID 生成算法,具有高性能、低延迟、且可排序的特点,适合 20 万 QPS 的高并发需求。
Snowflake 算法由 Twitter 开发,用于生成全局唯一的 64 位长整数 ID。其结构如下:
位置 | 位数 | 含义 |
|---|---|---|
符号位 | 1 位 | 总是 0,表示正数 |
时间戳 | 41 位 | 毫秒级时间戳,表示当前时间 |
数据中心 | 5 位 | 数据中心标识,支持 32 个数据中心 |
机器 ID | 5 位 | 机器节点标识,支持 32 台机器 |
序列号 | 12 位 | 毫秒内的自增序列号,支持每毫秒 4096 个 ID |
以下是基于 Java 的 Snowflake 算法实现:
public class SnowflakeIdGenerator {
// 开始时间戳(2024-01-01)
private final static long START_TIMESTAMP = 1704067200000L;
// 每部分占用的位数
private final static long DATA_CENTER_BITS = 5L; // 数据中心位数
private final static long MACHINE_BITS = 5L; // 机器ID位数
private final static long SEQUENCE_BITS = 12L; // 序列号位数
// 最大值
private final static long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_BITS);
private final static long MAX_MACHINE_ID = ~(-1L << MACHINE_BITS);
private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
// 位移
private final static long MACHINE_SHIFT = SEQUENCE_BITS;
private final static long DATA_CENTER_SHIFT = SEQUENCE_BITS + MACHINE_BITS;
private final static long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_BITS + DATA_CENTER_BITS;
private long dataCenterId; // 数据中心ID
private long machineId; // 机器ID
private long sequence = 0L; // 当前毫秒内序列号
private long lastTimestamp = -1L; // 上一次生成ID的时间戳
public SnowflakeIdGenerator(long dataCenterId, long machineId) {
if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
throw new IllegalArgumentException("DataCenterId out of range.");
}
if (machineId > MAX_MACHINE_ID || machineId < 0) {
throw new IllegalArgumentException("MachineId out of range.");
}
this.dataCenterId = dataCenterId;
this.machineId = machineId;
}
public synchronized long nextId() {
long currentTimestamp = getCurrentTimestamp();
if (currentTimestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate ID.");
}
if (currentTimestamp == lastTimestamp) {
// 同一毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0) {
// 序列号用尽,阻塞到下一毫秒
currentTimestamp = waitForNextMillis(currentTimestamp);
}
} else {
// 新的毫秒开始,序列号重置
sequence = 0L;
}
lastTimestamp = currentTimestamp;
return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
| (dataCenterId << DATA_CENTER_SHIFT)
| (machineId << MACHINE_SHIFT)
| sequence;
}
private long getCurrentTimestamp() {
return System.currentTimeMillis();
}
private long waitForNextMillis(long lastTimestamp) {
long timestamp = getCurrentTimestamp();
while (timestamp <= lastTimestamp) {
timestamp = getCurrentTimestamp();
}
return timestamp;
}
public static void main(String[] args) {
SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
for (int i = 0; i < 10; i++) {
System.out.println(generator.nextId());
}
}
}在单节点情况下,该实现可以达到 40 万 QPS 的性能,完全满足 20 万 QPS 的需求。
为了避免单点故障,随机 ID 服务需要分布式部署。以下是推荐的部署架构:
dataCenterId 和 machineId。通过 Snowflake 算法,我们可以构建一个高效、可靠的随机 ID 生成服务,支持 20 万 QPS 的高并发需求。同时,通过合理的分布式部署,确保服务的高可用性和可扩展性。
关键点总结:
这套方案可以广泛应用于各种需要高并发 ID 生成的场景,如电商平台、金融服务、社交网络等。希望本文能够帮助开发者更好地理解和实现高性能随机 ID 生成服务。