雪花算法(Snowflake ID)是 Twitter 開源的一種分布式 ID 生成算法,其目的是生成全局唯一的 ID。該算法的核心思想是將一個 64 位的二進制數字分成幾個部分,每個部分表示不同的信息,例如數據中心ID、機器ID、序列號等。這些部分的取值范圍可以根據實際情況進行調整。
使用雪花算法生成的 ID 具有以下特點:
- 全局唯一,ID 不會重復。
- 按時間有序,新生成的 ID 比舊的 ID 大。
- 可以在分布式環境下生成,不需要中心節點協調。
- 高性能,生成 ID 的速度快。
因其具有全局唯一和分布式特性,常被用于互聯網應用的分布式系統中,如訂單號生成、數據庫主鍵生成等。
具體實現代碼如下:
public class Snowflake {/** 開始時間戳 (2021-01-01) */private final long START_TIMESTAMP = 1609430400000L;/** 機器ID所占的位數 */private final long WORKER_ID_BITS = 5L;/** 數據標識ID所占的位數 */private final long DATA_CENTER_ID_BITS = 5L;/** 支持的最大機器ID,結果是31 (0B11111) */private final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);/** 支持的最大數據標識ID,結果是31 (0B11111) */private final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);/** 序列在ID中占的位數 */private final long SEQUENCE_BITS = 12L;/** 機器ID向左移12位 */private final long WORKER_ID_SHIFT = SEQUENCE_BITS;/** 數據標識ID向左移17位(12+5) */private final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;/** 時間戳向左移22位(5+5+12) */private final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;/** 支持的最大序列號,結果是4095 (0B111111111111) */private final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);/** 工作機器ID */private final long workerId;/** 數據中心ID */private final long dataCenterId;/** 毫秒內序列號 */private long sequence = 0L;/** 上次生成ID的時間戳 */private long lastTimestamp = -1L;/*** 構造函數* @param workerId 工作機器ID* @param dataCenterId 數據中心ID*/public Snowflake(long workerId, long dataCenterId) {if (workerId > MAX_WORKER_ID || workerId < 0) {throw new IllegalArgumentException(String.format("WorkerID不能超過%d且不能小于0", MAX_WORKER_ID));}if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {throw new IllegalArgumentException(String.format("DataCenterID不能超過%d且不能小于0", MAX_DATA_CENTER_ID));}this.workerId = workerId;this.dataCenterId = dataCenterId;}/*** 生成ID* @return long類型的ID*/public synchronized long nextId() {long timestamp = System.currentTimeMillis();// 如果當前時間小于上次生成ID的時間戳,說明系統時鐘回退過,拋出異常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("系統時鐘回退,拒絕生成ID,上次生成ID的時間戳:%d,當前時間戳:%d",lastTimestamp, timestamp));}// 如果當前時間等于上次生成ID的時間戳(同一毫秒內),則序列號加1if (timestamp == lastTimestamp) {sequence = (sequence + 1) & MAX_SEQUENCE;if (sequence == 0) {// 如果序列號已經超過最大值,需要等待到下一毫秒再繼續生成IDtimestamp = waitNextMillis(timestamp);}} else {sequence = 0L;}// 更新上次生成ID的時間戳lastTimestamp = timestamp;// 生成IDreturn ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT) |(dataCenterId << DATA_CENTER_ID_SHIFT) |(workerId << WORKER_ID_SHIFT) |sequence;}/*** 等待下一毫秒* @param timestamp 上次生成ID的時間戳* @return 下一毫秒的時間戳*/private long waitNextMillis(long timestamp) {long nextTimestamp = System.currentTimeMillis();while (nextTimestamp <= timestamp) {nextTimestamp = System.currentTimeMillis();}return nextTimestamp;}// 示例public static void main(String[] args) {Snowflake snowflake = new Snowflake(1, 1);System.out.println(snowflake.nextId());}
}
在上述代碼中,可以通過調整START_TIMESTAMP、WORKER_ID_BITS、DATA_CENTER_ID_BITS、SEQUENCE_BITS等參數來滿足不同的需求,例如支持更多的機器、更高的QPS等。
這是批量生成的ID: