溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java怎么通過手寫分布式雪花SnowFlake生成ID

發布時間:2022-04-08 09:09:35 來源:億速云 閱讀:336 作者:iii 欄目:開發技術

Java怎么通過手寫分布式雪花SnowFlake生成ID

目錄

  1. 引言
  2. SnowFlake算法簡介
  3. SnowFlake算法的核心思想
  4. SnowFlake算法的實現步驟
  5. Java實現SnowFlake算法
  6. SnowFlake算法的優缺點
  7. SnowFlake算法的應用場景
  8. 總結

引言

在分布式系統中,生成全局唯一的ID是一個常見的需求。傳統的自增ID在單機環境下可以很好地工作,但在分布式系統中,由于多個節點同時生成ID,可能會導致ID沖突。為了解決這個問題,Twitter提出了一種名為SnowFlake的算法,它可以在分布式系統中生成全局唯一的ID。本文將詳細介紹SnowFlake算法的原理,并通過Java代碼實現一個簡單的SnowFlake ID生成器。

SnowFlake算法簡介

SnowFlake算法是Twitter在2010年開源的一種分布式ID生成算法。它可以在分布式系統中生成全局唯一的ID,且生成的ID具有時間有序性。SnowFlake算法的核心思想是將一個64位的ID分成多個部分,每個部分代表不同的信息,如時間戳、機器ID、序列號等。

SnowFlake算法的核心思想

SnowFlake算法的核心思想是將一個64位的ID分成以下幾個部分:

  1. 時間戳(41位):表示生成ID的時間,精確到毫秒。41位的時間戳可以表示大約69年的時間。
  2. 機器ID(10位):表示生成ID的機器或節點。10位的機器ID可以表示1024個不同的機器。
  3. 序列號(12位):表示在同一毫秒內生成的ID的序列號。12位的序列號可以表示4096個不同的ID。

通過將ID分成這些部分,SnowFlake算法可以在分布式系統中生成全局唯一的ID,且生成的ID具有時間有序性。

SnowFlake算法的實現步驟

  1. 獲取當前時間戳:首先獲取當前的時間戳,精確到毫秒。
  2. 比較時間戳:如果當前時間戳小于上一次生成ID的時間戳,說明系統時鐘回退,此時需要等待時鐘追上。
  3. 生成序列號:如果當前時間戳等于上一次生成ID的時間戳,則遞增序列號。如果序列號超過最大值,則等待下一毫秒。
  4. 生成ID:將時間戳、機器ID和序列號組合成一個64位的ID。

Java實現SnowFlake算法

下面是一個簡單的Java實現SnowFlake算法的代碼:

public class SnowFlake {

    // 起始的時間戳
    private final static long START_STMP = 1480166465631L;

    // 每一部分占用的位數
    private final static long SEQUENCE_BIT = 12; // 序列號占用的位數
    private final static long MACHINE_BIT = 5;   // 機器標識占用的位數
    private final static long DATACENTER_BIT = 5;// 數據中心占用的位數

    // 每一部分的最大值
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

    // 每一部分向左的位移
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId;  // 數據中心
    private long machineId;     // 機器標識
    private long sequence = 0L; // 序列號
    private long lastStmp = -1L;// 上一次時間戳

    public SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    // 產生下一個ID
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            // 相同毫秒內,序列號自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            // 同一毫秒的序列數已經達到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            // 不同毫秒內,序列號置為0
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT // 時間戳部分
                | datacenterId << DATACENTER_LEFT       // 數據中心部分
                | machineId << MACHINE_LEFT             // 機器標識部分
                | sequence;                             // 序列號部分
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        SnowFlake snowFlake = new SnowFlake(2, 3);

        for (int i = 0; i < 10; i++) {
            System.out.println(snowFlake.nextId());
        }
    }
}

代碼解析

  1. 常量定義:定義了起始時間戳、各部分占用的位數、各部分的最大值以及各部分的位移。
  2. 構造函數:初始化數據中心ID和機器ID,并進行合法性檢查。
  3. nextId方法:生成下一個ID。首先獲取當前時間戳,如果當前時間戳小于上一次生成ID的時間戳,則拋出異常。如果當前時間戳等于上一次生成ID的時間戳,則遞增序列號;如果序列號超過最大值,則等待下一毫秒。最后將時間戳、數據中心ID、機器ID和序列號組合成一個64位的ID。
  4. getNextMill方法:獲取下一毫秒的時間戳。
  5. getNewstmp方法:獲取當前時間戳。
  6. main方法:測試SnowFlake算法的實現。

SnowFlake算法的優缺點

優點

  1. 高性能:SnowFlake算法生成ID的速度非???,每秒可以生成數百萬個ID。
  2. 分布式:SnowFlake算法可以在分布式系統中生成全局唯一的ID。
  3. 時間有序:生成的ID具有時間有序性,可以方便地按時間排序。

缺點

  1. 依賴系統時鐘:SnowFlake算法依賴于系統時鐘,如果系統時鐘回退,可能會導致ID沖突。
  2. 機器ID分配:需要手動分配機器ID,如果機器ID分配不當,可能會導致ID沖突。

SnowFlake算法的應用場景

  1. 分布式系統:在分布式系統中生成全局唯一的ID。
  2. 數據庫主鍵:作為數據庫表的主鍵,保證主鍵的唯一性。
  3. 消息隊列:在消息隊列中生成唯一的消息ID。

總結

SnowFlake算法是一種高效的分布式ID生成算法,它可以在分布式系統中生成全局唯一的ID,且生成的ID具有時間有序性。通過將ID分成時間戳、機器ID和序列號等部分,SnowFlake算法可以在分布式系統中生成高性能、高可用的ID。本文通過Java代碼實現了一個簡單的SnowFlake ID生成器,并介紹了SnowFlake算法的優缺點和應用場景。希望本文能幫助讀者更好地理解和使用SnowFlake算法。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女