首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

分布式系統全局唯一 ID 設計方案:從 UUID 到 Snowflake 變體

     編輯:Java 程式設計入門

核心需求

在分布式架構中,全局唯一 ID 作為資料庫主鍵,必須滿足兩大核心指標:

  1. 全局唯一:跨節點、跨機房不重複。
  2. 趨勢有序:盡可能遞增,利於 B+ 樹索引插入性能,減少頁面分裂。

主流方案對比

1. 資料庫自增

  • 優點:實現簡單,天然有序。
  • 缺點:單點寫入瓶頸,水平擴展困難,高併發下效能受限於單機 DB。

2. UUID (JDK UUID.randomUUID())

  • 優點:本地生成,無網路依賴,擴展性極佳。
  • 缺點:128-bit (36字符字串),空間佔用大;無時間戳,完全無序,索引效能極差;資訊密度低。

3. Twitter Snowflake 及其變體 (推薦)

核心思想:64-bit Long 型 ID,位元分配如下:

| 41 bits Timestamp (毫秒) | 10 bits WorkerID (機器) | 12 bits Sequence (序列) |
  • 單機每秒理論上限:1000 * 2^12 = 409.6 萬,滿足絕大多數業務。
  • 時間戳保證宏觀遞增;機器 ID 保證分布式唯一;序列號解決同毫秒內衝突。

自定義 64-bit ID 實作 (含機房區隔)

根據業務擴展需求,可調整位元分配,例如引入「區域/機房」位元:

| 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(); }
}

生產環境關鍵注意事項

  1. 時鐘同步:必須部署 NTP 服務,防止時鐘回撥導致 ID 重複或拋異常。
  2. 序列號隨機化:跨毫秒重置時使用隨機數 (0-9),避免序列號固定為 0 導致取模分布不均。
  3. 單例模式:應用內需保證生成器為單例,防止 WorkerID 衝突或序列號重置。
  4. WorkerID 分配:可結合 Zookeeper/Etcd/Consul 自動分配,或基於 K8s Pod IP/宿主機 IP 衍生。

總結

Snowflake 變體是目前分布式 ID 生成的主流選型,兼顧了效能、有序性與擴展性。實作時務必重視時鐘回撥防護與單例管理,並根據業務規模合理規劃位元分配 (機房/機器/業務模組)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved