亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁 php教程 php手冊 分布式系統(tǒng)唯一ID生成方案匯總

分布式系統(tǒng)唯一ID生成方案匯總

Sep 14, 2018 pm 01:39 PM
分布式

系統(tǒng)唯一ID是我們在設(shè)計(jì)一個(gè)系統(tǒng)的時(shí)候常常會遇見的問題,也常常為這個(gè)問題而糾結(jié)。生成ID的方法有很多,適應(yīng)不同的場景、需求以及性能要求。所以有些比較復(fù)雜的系統(tǒng)會有多個(gè)ID生成的策略。下面就介紹一些常見的ID生成策略。

一、數(shù)據(jù)庫自增長序列或字段?

最常見的方式。利用數(shù)據(jù)庫,全數(shù)據(jù)庫唯一。

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

  1. 簡單,代碼方便,性能可以接受。

  2. 數(shù)字ID天然排序,對分頁或者需要排序的結(jié)果很有幫助。

缺點(diǎn):

  1. 不同數(shù)據(jù)庫語法和實(shí)現(xiàn)不同,數(shù)據(jù)庫遷移的時(shí)候或多數(shù)據(jù)庫版本支持的時(shí)候需要處理。

  2. 在單個(gè)數(shù)據(jù)庫或讀寫分離或一主多從的情況下,只有一個(gè)主庫可以生成。有單點(diǎn)故障的風(fēng)險(xiǎn)。

  3. 在性能達(dá)不到要求的情況下,比較難于擴(kuò)展。

  4. 如果遇見多個(gè)系統(tǒng)需要合并或者涉及到數(shù)據(jù)遷移會相當(dāng)痛苦。

  5. 分表分庫的時(shí)候會有麻煩。

優(yōu)化方案:

  1. 針對主庫單點(diǎn),如果有多個(gè)Master庫,則每個(gè)Master庫設(shè)置的起始數(shù)字不一樣,步長一樣,可以是Master的個(gè)數(shù)。比如:Master1 生成的是 1,4,7,10,Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12。這樣就可以有效生成集群中的唯一ID,也可以大大降低ID生成數(shù)據(jù)庫操作的負(fù)載。

?

二、UUID 常見的方式。

可以利用數(shù)據(jù)庫也可以利用程序生成,一般來說全球唯一。

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

  1. 簡單,代碼方便。

  2. 生成ID性能非常好,基本不會有性能問題。

  3. 全球唯一,在遇見數(shù)據(jù)遷移,系統(tǒng)數(shù)據(jù)合并,或者數(shù)據(jù)庫變更等情況下,可以從容應(yīng)對。

缺點(diǎn):

  1. 沒有排序,無法保證趨勢遞增。

  2. UUID往往是使用字符串存儲,查詢的效率比較低。

  3. 存儲空間比較大,如果是海量數(shù)據(jù)庫,就需要考慮存儲量的問題。

  4. 傳輸數(shù)據(jù)量大

  5. 不可讀。

?

三、Redis生成ID?

當(dāng)使用數(shù)據(jù)庫來生成ID性能不夠要求的時(shí)候,我們可以嘗試使用Redis來生成ID。這主要依賴于Redis是單線程的,所以也可以用生成全局唯一的ID??梢杂肦edis的原子操作 INCR和INCRBY來實(shí)現(xiàn)。

可以使用Redis集群來獲取更高的吞吐量。假如一個(gè)集群中有5臺Redis??梢猿跏蓟颗_Redis的值分別是1,2,3,4,5,然后步長都是5。各個(gè)Redis生成的ID為:

A:1,6,11,16,21 B:2,7,12,17,22 C:3,8,13,18,23 D:4,9,14,19,24 E:5,10,15,20,25

這個(gè),隨便負(fù)載到哪個(gè)機(jī)確定好,未來很難做修改。但是3-5臺服務(wù)器基本能夠滿足器上,都可以獲得不同的ID。但是步長和初始值一定需要事先需要了。使用Redis集群也可以方式單點(diǎn)故障的問題。

另外,比較適合使用Redis來生成每天從0開始的流水號。比如訂單號=日期+當(dāng)日自增長號??梢悦刻煸赗edis中生成一個(gè)Key,使用INCR進(jìn)行累加。

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

  1. 不依賴于數(shù)據(jù)庫,靈活方便,且性能優(yōu)于數(shù)據(jù)庫。

  2. 數(shù)字ID天然排序,對分頁或者需要排序的結(jié)果很有幫助。

缺點(diǎn):

  1. 如果系統(tǒng)中沒有Redis,還需要引入新的組件,增加系統(tǒng)復(fù)雜度。

  2. 需要編碼和配置的工作量比較大。

?

四、Twitter的snowflake算法?

snowflake是Twitter開源的分布式ID生成算法,結(jié)果是一個(gè)long型的ID。其核心思想是:使用41bit作為毫秒數(shù),10bit作為機(jī)器的ID(5個(gè)bit是數(shù)據(jù)中心,5個(gè)bit的機(jī)器ID),12bit作為毫秒內(nèi)的流水號(意味著每個(gè)節(jié)點(diǎn)在每毫秒可以產(chǎn)生 4096 個(gè) ID),最后還有一個(gè)符號位,永遠(yuǎn)是0。具體實(shí)現(xiàn)的代碼可以參看:https://github.com/twitter/snowflake

public class IdWorker {
// ==============================Fields===========================================
/** 開始時(shí)間截 (2015-01-01) */
private final long twepoch = 1420041600000L;

/** 機(jī)器id所占的位數(shù) */
private final long workerIdBits = 5L;

/** 數(shù)據(jù)標(biāo)識id所占的位數(shù) */
private final long datacenterIdBits = 5L;

/** 支持的最大機(jī)器id,結(jié)果是31 (這個(gè)移位算法可以很快的計(jì)算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù)) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

/** 支持的最大數(shù)據(jù)標(biāo)識id,結(jié)果是31 */
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=0xfff=4095) */
private final long sequenceMask = -1L ^ (-1L << sequenceBits);

/** 工作機(jī)器ID(0~31) */
private long workerId;

/** 數(shù)據(jù)中心ID(0~31) */
private long datacenterId;

/** 毫秒內(nèi)序列(0~4095) */
private long sequence = 0L;

/** 上次生成ID的時(shí)間截 */
private long lastTimestamp = -1L;

//==============================Constructors=====================================
/**
 * 構(gòu)造函數(shù)
 * @param workerId 工作ID (0~31)
 * @param datacenterId 數(shù)據(jù)中心ID (0~31)
 */
public IdWorker(long workerId, long datacenterId) {
    if (workerId > maxWorkerId || workerId < 0) {
        throw new IllegalArgumentException(String.format("worker Id can&#39;t be greater than %d or less than 0", maxWorkerId));
    }
    if (datacenterId > maxDatacenterId || datacenterId < 0) {
        throw new IllegalArgumentException(String.format("datacenter Id can&#39;t be greater than %d or less than 0", maxDatacenterId));
    }
    this.workerId = workerId;
    this.datacenterId = datacenterId;
}

// ==============================Methods==========================================
/**
 * 獲得下一個(gè)ID (該方法是線程安全的)
 * @return SnowflakeId
 */
public synchronized long nextId() {
    long timestamp = timeGen();

    //如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳,說明系統(tǒng)時(shí)鐘回退過這個(gè)時(shí)候應(yīng)當(dāng)拋出異常
    if (timestamp < lastTimestamp) {
        throw new RuntimeException(
                String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
    }

    //如果是同一時(shí)間生成的,則進(jìn)行毫秒內(nèi)序列
    if (lastTimestamp == timestamp) {
        sequence = (sequence + 1) & sequenceMask;
        //毫秒內(nèi)序列溢出
        if (sequence == 0) {
            //阻塞到下一個(gè)毫秒,獲得新的時(shí)間戳
            timestamp = tilNextMillis(lastTimestamp);
        }
    }
    //時(shí)間戳改變,毫秒內(nèi)序列重置
    else {
        sequence = 0L;
    }

    //上次生成ID的時(shí)間截
    lastTimestamp = timestamp;

    //移位并通過或運(yùn)算拼到一起組成64位的ID
    return ((timestamp - twepoch) << timestampLeftShift) //
            | (datacenterId << datacenterIdShift) //
            | (workerId << workerIdShift) //
            | sequence;
}

/**
 * 阻塞到下一個(gè)毫秒,直到獲得新的時(shí)間戳
 * @param lastTimestamp 上次生成ID的時(shí)間截
 * @return 當(dāng)前時(shí)間戳
 */
protected long tilNextMillis(long lastTimestamp) {
    long timestamp = timeGen();
    while (timestamp <= lastTimestamp) {
        timestamp = timeGen();
    }
    return timestamp;
}

/**
 * 返回以毫秒為單位的當(dāng)前時(shí)間
 * @return 當(dāng)前時(shí)間(毫秒)
 */
protected long timeGen() {
    return System.currentTimeMillis();
}

//==============================Test=============================================
/** 測試 */
public static void main(String[] args) {
    IdWorker idWorker = new IdWorker(0, 0);
    for (int i = 0; i < 1000; i++) {
        long id = idWorker.nextId();
        System.out.println(Long.toBinaryString(id));
        System.out.println(id);
    }
}}

snowflake算法可以根據(jù)自身項(xiàng)目的需要進(jìn)行一定的修改。比如估算未來的數(shù)據(jù)中心個(gè)數(shù),每個(gè)數(shù)據(jù)中心的機(jī)器數(shù)以及統(tǒng)一毫秒可以能的并發(fā)數(shù)來調(diào)整在算法中所需要的bit數(shù)。

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

  1. 不依賴于數(shù)據(jù)庫,靈活方便,且性能優(yōu)于數(shù)據(jù)庫。

  2. ID按照時(shí)間在單機(jī)上是遞增的。

缺點(diǎn):

  1. 在單機(jī)上是遞增的,但是由于涉及到分布式環(huán)境,每臺機(jī)器上的時(shí)鐘不可能完全同步,也許有時(shí)候也會出現(xiàn)不是全局遞增的情況。

五、利用zookeeper生成唯一ID?

zookeeper主要通過其znode數(shù)據(jù)版本來生成序列號,可以生成32位和64位的數(shù)據(jù)版本號,客戶端可以使用這個(gè)版本號來作為唯一的序列號。

很少會使用zookeeper來生成唯一ID。主要是由于需要依賴zookeeper,并且是多步調(diào)用API,如果在競爭較大的情況下,需要考慮使用分布式鎖。因此,性能在高并發(fā)的分布式環(huán)境下,也不甚理想。

六、MongoDB的ObjectId?

MongoDB的ObjectId和snowflake算法類似。它設(shè)計(jì)成輕量型的,不同的機(jī)器都能用全局唯一的同種方法方便地生成它。MongoDB 從一開始就設(shè)計(jì)用來作為分布式數(shù)據(jù)庫,處理多個(gè)節(jié)點(diǎn)是一個(gè)核心要求。使其在分片環(huán)境中要容易生成得多。其格式如下: [src/main/resources/objectId.png] 這里寫圖片描述:

20180914090405298.png

前4 個(gè)字節(jié)是從標(biāo)準(zhǔn)紀(jì)元開始的時(shí)間戳,單位為秒。時(shí)間戳,與隨后的5 個(gè)字節(jié)組合起來,提供了秒級別的唯一性。由于時(shí)間戳在前,這意味著ObjectId 大致會按照插入的順序排列。這對于某些方面很有用,如將其作為索引提高效率。這4 個(gè)字節(jié)也隱含了文檔創(chuàng)建的時(shí)間。絕大多數(shù)客戶端類庫都會公開一個(gè)方法從ObjectId 獲取這個(gè)信息。 接下來的3 字節(jié)是所在主機(jī)的唯一標(biāo)識符。通常是機(jī)器主機(jī)名的散列值。這樣就可以確保不同主機(jī)生成不同的ObjectId,不產(chǎn)生沖突。 為了確保在同一臺機(jī)器上并發(fā)的多個(gè)進(jìn)程產(chǎn)生的ObjectId 是唯一的,接下來的兩字節(jié)來自產(chǎn)生ObjectId 的進(jìn)程標(biāo)識符(PID)。 前9 字節(jié)保證了同一秒鐘不同機(jī)器不同進(jìn)程產(chǎn)生的ObjectId 是唯一的。后3 字節(jié)就是一個(gè)自動(dòng)增加的計(jì)數(shù)器,確保相同進(jìn)程同一秒產(chǎn)生的ObjectId 也是不一樣的。同一秒鐘最多允許每個(gè)進(jìn)程擁有2563(16 777 216)個(gè)不同的ObjectId。

相關(guān)推薦:

php新聞發(fā)布管理系統(tǒng)開發(fā)實(shí)例

PHP開發(fā)簡單的新聞發(fā)布系統(tǒng)教程

以上是分布式系統(tǒng)唯一ID生成方案匯總的詳細(xì)內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級代碼編輯軟件(SublimeText3)

如何使用Redis實(shí)現(xiàn)分布式數(shù)據(jù)同步 如何使用Redis實(shí)現(xiàn)分布式數(shù)據(jù)同步 Nov 07, 2023 pm 03:55 PM

如何使用Redis實(shí)現(xiàn)分布式數(shù)據(jù)同步隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展和應(yīng)用場景的日益復(fù)雜,分布式系統(tǒng)的概念越來越被廣泛采用。在分布式系統(tǒng)中,數(shù)據(jù)同步是一個(gè)重要的問題。Redis作為一個(gè)高性能的內(nèi)存數(shù)據(jù)庫,不僅可以用來存儲數(shù)據(jù),還可以用來實(shí)現(xiàn)分布式數(shù)據(jù)同步。對于分布式數(shù)據(jù)同步,一般有兩種常見的模式:發(fā)布/訂閱(Publish/Subscribe)模式和主從復(fù)制(Maste

Redis如何實(shí)現(xiàn)分布式會話管理 Redis如何實(shí)現(xiàn)分布式會話管理 Nov 07, 2023 am 11:10 AM

Redis如何實(shí)現(xiàn)分布式會話管理,需要具體代碼示例分布式會話管理是當(dāng)下互聯(lián)網(wǎng)熱門話題之一,面對高并發(fā)、大數(shù)據(jù)量的場景,傳統(tǒng)的會話管理方式逐漸顯得力不從心。Redis作為一個(gè)高性能的鍵值數(shù)據(jù)庫,提供了分布式會話管理的解決方案。本文將介紹如何使用Redis實(shí)現(xiàn)分布式會話管理,并給出具體的代碼示例。一、Redis作為分布式會話存儲介紹傳統(tǒng)的會話管理方式是將會話信

如何使用Swoole實(shí)現(xiàn)分布式定時(shí)任務(wù)調(diào)度 如何使用Swoole實(shí)現(xiàn)分布式定時(shí)任務(wù)調(diào)度 Nov 07, 2023 am 11:04 AM

如何使用Swoole實(shí)現(xiàn)分布式定時(shí)任務(wù)調(diào)度引言:在傳統(tǒng)的PHP開發(fā)中,我們經(jīng)常會使用cron來實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度,但是cron只能在單臺服務(wù)器上執(zhí)行任務(wù),無法應(yīng)對高并發(fā)的場景。而Swoole是一款基于PHP的高性能異步并發(fā)框架,它提供了完善的網(wǎng)絡(luò)通信能力和多進(jìn)程支持,使得我們能夠輕松實(shí)現(xiàn)分布式定時(shí)任務(wù)調(diào)度。本文將介紹如何使用Swoole來實(shí)現(xiàn)分布式定時(shí)任務(wù)調(diào)度

利用Redis實(shí)現(xiàn)分布式緩存一致性 利用Redis實(shí)現(xiàn)分布式緩存一致性 Nov 07, 2023 pm 12:05 PM

利用Redis實(shí)現(xiàn)分布式緩存一致性在現(xiàn)代分布式系統(tǒng)中,緩存起著非常重要的作用。它可以大大降低系統(tǒng)對數(shù)據(jù)庫的訪問頻率,提高系統(tǒng)的性能和吞吐量。而在分布式系統(tǒng)中,為了保證緩存的一致性,我們需要解決多個(gè)節(jié)點(diǎn)之間的數(shù)據(jù)同步問題。在本文中,我們將介紹如何利用Redis實(shí)現(xiàn)分布式緩存一致性,并給出具體的代碼示例。Redis是一個(gè)高性能的鍵值數(shù)據(jù)庫,它支持持久化、復(fù)制和集

利用MongoDB實(shí)現(xiàn)分布式任務(wù)調(diào)度與執(zhí)行的經(jīng)驗(yàn)分享 利用MongoDB實(shí)現(xiàn)分布式任務(wù)調(diào)度與執(zhí)行的經(jīng)驗(yàn)分享 Nov 02, 2023 am 09:39 AM

MongoDB是一個(gè)開源的NoSQL數(shù)據(jù)庫,具有高性能、伸縮性和靈活性的特點(diǎn)。在分布式系統(tǒng)中,任務(wù)調(diào)度與執(zhí)行是一個(gè)關(guān)鍵的問題,通過利用MongoDB的特性,可以實(shí)現(xiàn)分布式任務(wù)調(diào)度與執(zhí)行的方案。一、分布式任務(wù)調(diào)度的需求分析在分布式系統(tǒng)中,任務(wù)調(diào)度是將任務(wù)分配給不同的節(jié)點(diǎn)進(jìn)行執(zhí)行的過程。常見的任務(wù)調(diào)度需求包括:1.任務(wù)的請求分發(fā):將任務(wù)請求發(fā)送給可用的執(zhí)行節(jié)點(diǎn)。

Go語言開發(fā)實(shí)現(xiàn)分布式日志分析系統(tǒng)的方法與技巧 Go語言開發(fā)實(shí)現(xiàn)分布式日志分析系統(tǒng)的方法與技巧 Nov 20, 2023 am 10:23 AM

Go語言開發(fā)實(shí)現(xiàn)分布式日志分析系統(tǒng)的方法與技巧摘要:隨著大數(shù)據(jù)時(shí)代的到來,日志分析成為了企業(yè)必不可少的一項(xiàng)工作。本文介紹了以Go語言為基礎(chǔ),開發(fā)實(shí)現(xiàn)分布式日志分析系統(tǒng)的方法與技巧。文章從系統(tǒng)架構(gòu)設(shè)計(jì)、數(shù)據(jù)收集、分布式處理、數(shù)據(jù)存儲與查詢等方面進(jìn)行了詳細(xì)解析,為讀者提供了一套實(shí)用的指南。關(guān)鍵詞:Go語言;分布式系統(tǒng);日志分析一、引言隨著互聯(lián)網(wǎng)的快速發(fā)展和智能設(shè)

利用Redis實(shí)現(xiàn)分布式任務(wù)調(diào)度 利用Redis實(shí)現(xiàn)分布式任務(wù)調(diào)度 Nov 07, 2023 am 08:15 AM

利用Redis實(shí)現(xiàn)分布式任務(wù)調(diào)度隨著業(yè)務(wù)的擴(kuò)展和系統(tǒng)的發(fā)展,很多業(yè)務(wù)都需要實(shí)現(xiàn)分布式任務(wù)調(diào)度,以確保任務(wù)能夠在多個(gè)節(jié)點(diǎn)上同時(shí)執(zhí)行,從而提高系統(tǒng)的穩(wěn)定性和可用性。而Redis作為一款高性能的內(nèi)存數(shù)據(jù)存儲產(chǎn)品,具備分布式、高可用、高性能等特點(diǎn),很適合用于實(shí)現(xiàn)分布式任務(wù)調(diào)度。本文將介紹如何利用Redis實(shí)現(xiàn)分布式任務(wù)調(diào)度,并提供相應(yīng)的代碼示例。一、Redis的基

Golang與RabbitMQ實(shí)現(xiàn)分布式日志收集和分析的細(xì)節(jié)、技巧和最佳實(shí)踐 Golang與RabbitMQ實(shí)現(xiàn)分布式日志收集和分析的細(xì)節(jié)、技巧和最佳實(shí)踐 Sep 27, 2023 pm 12:31 PM

Golang與RabbitMQ實(shí)現(xiàn)分布式日志收集和分析的細(xì)節(jié)、技巧和最佳實(shí)踐最近幾年,隨著微服務(wù)架構(gòu)的流行和大規(guī)模系統(tǒng)的復(fù)雜化,日志的收集和分析變得越來越重要。在一個(gè)分布式系統(tǒng)中,各個(gè)微服務(wù)的日志往往分散在不同的地方,如何高效地收集和分析這些日志成為一個(gè)挑戰(zhàn)。本文將介紹如何使用Golang和RabbitMQ實(shí)現(xiàn)分布式日志收集和分析的細(xì)節(jié)、技巧和最佳實(shí)踐。Ra

See all articles