在分布式架構中,全局唯一 ID 作為資料庫主鍵,必須滿足兩大核心指標:
UUID.randomUUID())核心思想:64-bit Long 型 ID,位元分配如下:
| 41 bits Timestamp (毫秒) | 10 bits WorkerID (機器) | 12 bits Sequence (序列) |
1000 * 2^12 = 409.6 萬,滿足絕大多數業務。根據業務擴展需求,可調整位元分配,例如引入「區域/機房」位元:
| 41 bits Timestamp | 3 bits RegionID | 10 bits WorkerID | 10 bits Sequence |
public class CustomIdGenerator {
// 位元常量
private static final long REGION_BITS = 3L;
private static final long WORKER_BITS = 10L;
private static final long SEQUENCE_BITS = 10L;
// 最大值掩碼
private static final long MAX_REGION = -1L ^ (-1L << REGION_BITS);
private static final long MAX_WORKER = -1L ^ (-1L << WORKER_BITS);
private static final long SEQUENCE_MASK = -1L ^ (-1L << SEQUENCE_BITS);
// 位移量
private static final long WORKER_SHIFT = SEQUENCE_BITS;
private static final long REGION_SHIFT = SEQUENCE_BITS + WORKER_BITS;
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_BITS + REGION_BITS;
private final long workerId;
private final long regionId;
private long sequence = 0L;
private long lastTimestamp = -1L;
private final long twepoch = 1288834974657L; // 基準時間
public synchronized long nextId() {
long timestamp = timeGen();
// 時鐘回撥保護
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards: " + (lastTimestamp - timestamp) + "ms");
}
if (lastTimestamp == timestamp) {
// 同一毫秒內,序列遞增
sequence = (sequence + 1) & SEQUENCE_MASK;
if (sequence == 0) {
// 序列耗盡,自旋等待下一毫秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
// 新毫秒,序列重置為隨機數 (優化取模分布)
sequence = new SecureRandom().nextInt(10);
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << TIMESTAMP_SHIFT)
| (regionId << REGION_SHIFT)
| (workerId << WORKER_SHIFT)
| sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) timestamp = timeGen();
return timestamp;
}
protected long timeGen() { return System.currentTimeMillis(); }
}
Snowflake 變體是目前分布式 ID 生成的主流選型,兼顧了效能、有序性與擴展性。實作時務必重視時鐘回撥防護與單例管理,並根據業務規模合理規劃位元分配 (機房/機器/業務模組)。