最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java中使用雪花算法(Snowflake)為分布式系統(tǒng)生成全局唯一ID代碼示例

 更新時(shí)間:2024年07月19日 10:53:06   作者:Jack_abu  
Java雪花算法是一種用于生成唯一ID的算法,它可以在分布式系統(tǒng)中生成全局唯一的ID,這篇文章主要給大家介紹了關(guān)于java中使用雪花算法(Snowflake)為分布式系統(tǒng)生成全局唯一ID的相關(guān)資料,需要的朋友可以參考下

(全局唯一ID的解決方案有很多種,這里主要是介紹和學(xué)習(xí)Snowflake算法)

什么是雪花算法(Snowflake)

雪花算法(Snowflake Algorithm)是由Twitter公司在2010年左右提出的一種分布式ID生成算法,主要用于生成全局唯一且趨勢遞增的ID。這種算法生成的ID是一個(gè)64位的長整型數(shù)字,具有很高的性能與擴(kuò)展性,特別適合于分布式環(huán)境下的主鍵生成場景,比如數(shù)據(jù)庫表主鍵、消息隊(duì)列的Message ID等。

實(shí)現(xiàn)原理

Snowflake算法的原理主要體現(xiàn)在它生成64位ID的結(jié)構(gòu)上,主要?jiǎng)澐譃槿缦聨讉€(gè)部分:

0 | 00000000000000000000000000000000000000000 | 00000 | 00000 | 000000000000

  • 1bit-符號位:

第1位通常固定為0,表示生成的ID都是正數(shù)。

  • 41bit-時(shí)間戳部分:

從第2位到第42位(共41位)存儲時(shí)間戳信息,精確到毫秒級別。時(shí)間戳可以是自定義的一個(gè)起始時(shí)間點(diǎn)(如Twitter使用的是2010-11-04的某一時(shí)刻),這樣可以通過比較ID中的時(shí)間戳部分來判斷事件發(fā)生的先后順序。41位的時(shí)間截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69。

  • 10bit-工作機(jī)器ID(5bit數(shù)據(jù)中心ID+5bit機(jī)器ID):

從第43位到第52位(共10位)存儲工作機(jī)器ID或者數(shù)據(jù)中心ID。這部分可以進(jìn)一步細(xì)分為兩部分,例如前5位標(biāo)識數(shù)據(jù)中心ID,后5位標(biāo)識工作節(jié)點(diǎn)ID。這樣可以支持32(0~31)個(gè)數(shù)據(jù)中心以及每個(gè)數(shù)據(jù)中心內(nèi)部的32(0~31)個(gè)工作節(jié)點(diǎn),足夠覆蓋大規(guī)模分布式系統(tǒng)的節(jié)點(diǎn)標(biāo)識。

  • 12bit-序列號部分:

從第53位到第64位(共12位)存儲同一節(jié)點(diǎn)同一毫秒內(nèi)生成的序列號,這意味著同一個(gè)節(jié)點(diǎn)在同毫秒內(nèi)可以生成最多4096個(gè)不同的ID(2^12)。

當(dāng)生成ID時(shí),首先獲取當(dāng)前時(shí)間戳,然后加上工作節(jié)點(diǎn)ID以及序列號。如果在同一毫秒內(nèi)有新的請求,則序列號加1。若序列號達(dá)到最大值,則等待下一毫秒再進(jìn)行分配,從而確保在同一節(jié)點(diǎn)內(nèi)生成的ID是唯一的

雪花算法的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 全局唯一性:雪花算法生成的ID是全局唯一的,這在分布式系統(tǒng)中非常重要,可以避免因ID沖突而導(dǎo)致的數(shù)據(jù)不一致問題。

  • 遞增有序:由于ID中包含時(shí)間戳部分,所以生成的ID是遞增有序的。這有助于數(shù)據(jù)庫插入性能的優(yōu)化,因?yàn)橛行虻腎D可以減少數(shù)據(jù)庫的頁分裂,提高寫入效率。

  • 靈活性:雪花算法允許自定義配置工作機(jī)器ID和數(shù)據(jù)中心ID的位數(shù),可以根據(jù)實(shí)際部署環(huán)境調(diào)整這些配置,以支持不同規(guī)模的分布式系統(tǒng)。

  • 高效性:算法本身實(shí)現(xiàn)簡單,生成ID的速度快,能夠滿足高并發(fā)場景下的需求。

缺點(diǎn):

  • 時(shí)鐘依賴:雪花算法依賴于系統(tǒng)時(shí)鐘來生成時(shí)間戳部分。如果系統(tǒng)時(shí)鐘出現(xiàn)回?fù)芑蚱?,可能會?dǎo)致生成的ID不唯一或有序性受到破壞。雖然可以通過一些機(jī)制來處理時(shí)鐘回?fù)軉栴},但時(shí)鐘漂移仍然是一個(gè)潛在的風(fēng)險(xiǎn)。

  • 機(jī)器ID沖突:如果部署的工作節(jié)點(diǎn)數(shù)量超過了算法中定義的機(jī)器ID位數(shù)所能表示的范圍,就會發(fā)生機(jī)器ID沖突。這需要在設(shè)計(jì)系統(tǒng)時(shí)預(yù)先規(guī)劃好機(jī)器ID的分配和管理。

  • 缺乏安全性:雪花算法生成的ID本身并不包含加密或簽名信息,因此容易受到惡意篡改。如果ID的安全性要求較高,需要在生成ID后添加額外的加密或簽名措施。

  • 擴(kuò)展性限制:由于雪花算法的ID結(jié)構(gòu)是固定的,因此在某些情況下可能會受到擴(kuò)展性的限制。例如,如果未來需要添加更多的元數(shù)據(jù)到ID中,或者需要支持更大的分布式系統(tǒng)規(guī)模,可能需要重新設(shè)計(jì)ID生成算法。

因此,為了更全面地解決雪花算法的缺陷問題,可能需要采取額外的措施,例如:

  • 增強(qiáng)時(shí)鐘同步:使用NTP(Network Time Protocol)或其他時(shí)鐘同步機(jī)制來確保各個(gè)節(jié)點(diǎn)之間的時(shí)鐘盡可能準(zhǔn)確同步。

  • 增加機(jī)器ID的靈活性:設(shè)計(jì)一種更靈活的方式來分配和管理機(jī)器ID,以便支持更多的工作節(jié)點(diǎn)和數(shù)據(jù)中心。

  • 安全性考慮:對生成的ID進(jìn)行加密或簽名,以防止惡意篡改。

綜上所述,雪花算法在分布式系統(tǒng)中具有廣泛的應(yīng)用價(jià)值,其全局唯一性和遞增有序性使得它成為生成唯一ID的優(yōu)選方案之一。然而,在使用雪花算法時(shí)也需要注意其潛在的缺點(diǎn),并根據(jù)實(shí)際需求進(jìn)行配置和優(yōu)化。

Snowflake算法生成ID的Java代碼示例

以下是Snowflake算法的一個(gè)java簡化版實(shí)現(xiàn):

public class SnowflakeIdWorker {  
    // 起始的時(shí)間戳(自定義,例如系統(tǒng)上線時(shí)間)  
    private final long twepoch = 1288834974657L;  
  
    // 機(jī)器id所占的位數(shù)  
    private final long workerIdBits = 5L;  
  
    // 數(shù)據(jù)標(biāo)識id所占的位數(shù)  
    private final long datacenterIdBits = 5L;  
  
    // 最大機(jī)器ID  
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);  
  
    // 最大數(shù)據(jù)標(biāo)識ID  
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);  
  
    // 序列在id中占的位數(shù)  
    private final long sequenceBits = 12L;  
  
    // 機(jī)器ID左移12位  
    private final long workerIdShift = sequenceBits;  
  
    // 數(shù)據(jù)標(biāo)識id左移17位(12+5)  
    private final long datacenterIdShift = sequenceBits + workerIdBits;  
  
    // 時(shí)間截左移22位(5+5+12)  
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;  
  
    // 序列的掩碼,這里為4095 (0b111111111111=4095)  
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);  
  
    // 上次生成ID的時(shí)間截  
    private long lastTimestamp = -1L;  
  
    // 序列號  
    private long sequence = 0L;  
  
    // 工作機(jī)器ID  
    private final long workerId;  
  
    // 數(shù)據(jù)中心ID  
    private final long datacenterId;  
  
    public SnowflakeIdWorker(long workerId, long datacenterId) {  
        if (workerId > maxWorkerId || workerId < 0) {  
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));  
        }  
        if (datacenterId > maxDatacenterId || datacenterId < 0) {  
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));  
        }  
        this.workerId = workerId;  
        this.datacenterId = datacenterId;  
    }    
  
    // 生成ID  
    public synchronized long nextId() {  
        long timestamp = timeGen();  
  
        // 如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳,說明系統(tǒng)時(shí)鐘回退,拋出異常  
        if (timestamp < lastTimestamp) {  
            throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));  
        }  
  
        // 如果時(shí)間戳相同,則序列號自增  
        if (lastTimestamp == timestamp) {  
            sequence = (sequence + 1) & sequenceMask;  
            // 序列號溢出,等待下一毫秒  
            if (sequence == 0) {  
                timestamp = tilNextMillis(lastTimestamp);  
            }  
        } else {  
            // 時(shí)間戳改變,序列號重置為0  
            sequence = 0L;  
        }  
  
        // 更新最后的時(shí)間戳  
        lastTimestamp = timestamp;  
  
        // 移位并通過或運(yùn)算拼到一起組成64位的ID  
        return ((timestamp - twepoch) << timestampLeftShift) |  
               (datacenterId << datacenterIdShift) |  
               (workerId << workerIdShift) |  
               sequence;  
    }  
  
    // 獲取當(dāng)前時(shí)間戳  
    protected long timeGen() {  
        return System.currentTimeMillis();  
    }  
  
    // 等待下一個(gè)毫秒  
    protected long tilNextMillis(long lastTimestamp) {  
        long timestamp = timeGen();  
        while (timestamp <= lastTimestamp) {  
            timestamp = timeGen();  
        }  
        return timestamp;  
    }

    public static void main(String[] args) {  
        SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 1);  
        for (int i = 0; i < 5; i++) {  
            long id = idWorker.nextId();  
            System.out.println(Long.toBinaryString(id));  
            System.out.println(id);  
        }  
    }  
}

代碼輸出:

這段代碼實(shí)現(xiàn)了雪花算法的核心邏輯。在nextId()方法中,它首先獲取當(dāng)前時(shí)間戳,然后檢查時(shí)間戳是否小于上一次生成ID時(shí)的時(shí)間戳,如果是,則拋出異常,因?yàn)檫@意味著系統(tǒng)時(shí)鐘回退,可能會導(dǎo)致ID生成出現(xiàn)混亂。如果時(shí)間戳相同,則序列號自增,并檢查是否溢出,如果溢出則等待下一個(gè)毫秒。如果時(shí)間戳不同,則重置序列號。最后,將時(shí)間戳、數(shù)據(jù)中心ID、機(jī)器ID和序列號按照各自的偏移量左移,然后進(jìn)行位或運(yùn)算,組合成一個(gè)64位的ID。

(注:關(guān)于數(shù)據(jù)中心ID、機(jī)器ID,根據(jù)實(shí)際情況來進(jìn)行配置。)

總結(jié)

到此這篇關(guān)于java中使用雪花算法(Snowflake)為分布式系統(tǒng)生成全局唯一ID的文章就介紹到這了,更多相關(guān)java雪花算法生成全局唯一ID內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

西峡县| 莆田市| 玉环县| 天镇县| 景洪市| 长治市| 漳浦县| 池州市| 山东省| 集贤县| 石首市| 惠州市| 米林县| 建始县| 紫金县| 伊宁市| 渝北区| 崇州市| 白朗县| 紫阳县| 兴国县| 武宣县| 长泰县| 旬邑县| 恩施市| 称多县| 邮箱| 宁国市| 太仆寺旗| 武乡县| 呼和浩特市| 思南县| 彰化县| 房山区| 岳阳县| 聊城市| 河源市| 城口县| 阿荣旗| 兴化市| 安宁市|