欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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生成算法,主要用于生成全局唯一且趨勢(shì)遞增的ID。這種算法生成的ID是一個(gè)64位的長整型數(shù)字,具有很高的性能與擴(kuò)展性,特別適合于分布式環(huán)境下的主鍵生成場(chǎng)景,比如數(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-符號(hào)位:

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

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

從第2位到第42位(共41位)存儲(chǔ)時(shí)間戳信息,精確到毫秒級(jí)別。時(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位)存儲(chǔ)工作機(jī)器ID或者數(shù)據(jù)中心ID。這部分可以進(jìn)一步細(xì)分為兩部分,例如前5位標(biāo)識(shí)數(shù)據(jù)中心ID,后5位標(biāo)識(shí)工作節(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)識(shí)。

  • 12bit-序列號(hào)部分:

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

當(dāng)生成ID時(shí),首先獲取當(dāng)前時(shí)間戳,然后加上工作節(jié)點(diǎn)ID以及序列號(hào)。如果在同一毫秒內(nèi)有新的請(qǐng)求,則序列號(hào)加1。若序列號(hào)達(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ā)場(chǎng)景下的需求。

缺點(diǎn):

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

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

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

  • 擴(kuò)展性限制:由于雪花算法的ID結(jié)構(gòu)是固定的,因此在某些情況下可能會(huì)受到擴(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ù)中心。

  • 安全性考慮:對(duì)生成的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)識(shí)id所占的位數(shù)  
    private final long datacenterIdBits = 5L;  
  
    // 最大機(jī)器ID  
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);  
  
    // 最大數(shù)據(jù)標(biāo)識(shí)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)識(shí)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;  
  
    // 序列號(hào)  
    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í)間戳相同,則序列號(hào)自增  
        if (lastTimestamp == timestamp) {  
            sequence = (sequence + 1) & sequenceMask;  
            // 序列號(hào)溢出,等待下一毫秒  
            if (sequence == 0) {  
                timestamp = tilNextMillis(lastTimestamp);  
            }  
        } else {  
            // 時(shí)間戳改變,序列號(hào)重置為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í)鐘回退,可能會(huì)導(dǎo)致ID生成出現(xiàn)混亂。如果時(shí)間戳相同,則序列號(hào)自增,并檢查是否溢出,如果溢出則等待下一個(gè)毫秒。如果時(shí)間戳不同,則重置序列號(hào)。最后,將時(shí)間戳、數(shù)據(jù)中心ID、機(jī)器ID和序列號(hào)按照各自的偏移量左移,然后進(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中HashMap的常見用法詳解

    Java中HashMap的常見用法詳解

    這篇文章主要介紹了Java中HashMap的常見用法詳解,HashMap是Java中的一個(gè)常用子類,它是java.util.HashMap<k,v>集合,實(shí)現(xiàn)了Map<k,v>接口, HashMap可以存儲(chǔ)鍵值對(duì),通過鍵來快速訪問值,在HashMap中,鍵是唯一的,而值可以重復(fù),需要的朋友可以參考下
    2023-09-09
  • Java?Map.values()方法之如何獲取Map集合中的所有鍵值對(duì)象

    Java?Map.values()方法之如何獲取Map集合中的所有鍵值對(duì)象

    這篇文章主要介紹了Java?Map.values()方法之如何獲取Map集合中的所有鍵值對(duì)象問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • ShardingSphere jdbc實(shí)現(xiàn)分庫分表核心概念詳解

    ShardingSphere jdbc實(shí)現(xiàn)分庫分表核心概念詳解

    這篇文章主要為大家介紹了ShardingSphere jdbc實(shí)現(xiàn)分庫分表核心概念詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • JSON反序列化Long變Integer或Double的問題及解決

    JSON反序列化Long變Integer或Double的問題及解決

    這篇文章主要介紹了JSON反序列化Long變Integer或Double的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java string不可變?cè)韺?shí)例解析

    Java string不可變?cè)韺?shí)例解析

    這篇文章主要介紹了Java string不可變?cè)韺?shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • SpringBoot解析yml全流程詳解

    SpringBoot解析yml全流程詳解

    本文主要介紹了SpringBoot解析yml全流程詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java 類在 Tomcat 中是如何加載的(過程分析)

    Java 類在 Tomcat 中是如何加載的(過程分析)

    這篇文章主要介紹了Java 類在 Tomcat 中是如何加載的過程分析,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • IDEA POM文件配置profile實(shí)現(xiàn)不同環(huán)境切換的方法步驟

    IDEA POM文件配置profile實(shí)現(xiàn)不同環(huán)境切換的方法步驟

    這篇文章主要介紹了IDEA POM文件配置profile實(shí)現(xiàn)不同環(huán)境切換的方法步驟
    2024-03-03
  • 基于ssm中dao接口@Param注解的用法

    基于ssm中dao接口@Param注解的用法

    這篇文章主要介紹了基于ssm中dao接口@Param注解的用法,具有很好的參考價(jià)值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 在SpringBoot中使用MongoDB完成數(shù)據(jù)存儲(chǔ)

    在SpringBoot中使用MongoDB完成數(shù)據(jù)存儲(chǔ)

    本文主要介紹了在SpringBoot中如惡化使用MongoDB完成數(shù)據(jù)存儲(chǔ),接下來這篇我們將圍繞MongoDB進(jìn)行,MongoDB是一個(gè)開源的,面向文檔的NoSQL數(shù)據(jù)庫管理系統(tǒng),使用類似JSON的BSON(二進(jìn)制JSON)格式來存儲(chǔ)數(shù)據(jù),具有靈活的數(shù)據(jù)模型和強(qiáng)大的查詢功能,需要的朋友可以參考下
    2023-11-11

最新評(píng)論