一文搞定分布式系統ID生成方案

2021-10-06 19:46:56 字數 4406 閱讀 8953

系統唯一id是我們在設計乙個系統的時候常常會遇見的問題,也常常為這個問題而糾結。生成id的方法有很多,適應不同的場景、需求以及效能要求。所以有些比較複雜的系統會有多個id生成的策略。下面就介紹一些常見的id生成策略。

資料庫自增長序列或字段

最常見的方式。利用資料庫,全資料庫唯一。

優點:1)簡單,**方便,效能可以接受。

2)數字id天然排序,對分頁或者需要排序的結果很有幫助。

缺點:1)不同資料庫語法和實現不同,資料庫遷移的時候或多資料庫版本支援的時候需要處理。

2)在單個資料庫或讀寫分離或一主多從的情況下,只有乙個主庫可以生成。有單點故障的風險。

3)在效能達不到要求的情況下,比較難於擴充套件。

4)如果遇見多個系統需要合併或者涉及到資料遷移會相當痛苦。

5)分表分庫的時候會有麻煩。

優化方案:

1)針對主庫單點,如果有多個master庫,則每個master庫設定的起始數字不一樣,步長一樣,可以是master的個數。比如:master1 生成的是 1,4,7,10,master2生成的是2,5,8,11 master3生成的是 3,6,9,12。這樣就可以有效生成集群中的唯一id,也可以大大降低id生成資料庫操作的負載。

uuid

常見的方式。可以利用資料庫也可以利用程式生成,一般來說全球唯一。

優點:1)簡單,**方便。

2)生成id效能非常好,基本不會有效能問題。

3)全球唯一,在遇見資料遷移,系統資料合併,或者資料庫變更等情況下,可以從容應對。

缺點:1)沒有排序,無法保證趨勢遞增。

2)uuid往往是使用字串儲存,查詢的效率比較低。

3)儲存空間比較大,如果是海量資料庫,就需要考慮儲存量的問題。

4)傳輸資料量大

5)不可讀。

uuid的變種

1)為了解決uuid不可讀,可以使用uuid to int64的方法。及

///

/// 根據guid獲取唯一數字序列

///

public static long guidtoint64()

2)為了解決uuid無序的問題,nhibernate在其主鍵生成方式中提供了comb演算法(combined guid/timestamp)。保留guid的10個位元組,用另6個位元組表示guid生成的時間(datetime)。

///

/// generate a new using the comb algorithm.

///

private guid generatecomb()

用上面的演算法測試一下,得到如下的結果:作為比較,前面3個是使用comb演算法得出的結果,最後12個字串是時間序(統一毫秒生成的3個uuid),過段時間如果再次生成,則12個字串會比圖示的要大。後面3個是直接生成的guid。

redis生成id

當使用資料庫來生成id效能不夠要求的時候,我們可以嘗試使用redis來生成id。這主要依賴於redis是單執行緒的,所以也可以用生成全域性唯一的id。可以用redis的原子操作 incr和incrby來實現。

可以使用redis集群來獲取更高的吞吐量。假如乙個集群中有5臺redis。可以初始化每台redis的值分別是1,2,3,4,5,然後步長都是5。各個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

這個,隨便負載到哪個機確定好,未來很難做修改。但是3-5臺伺服器基本能夠滿足器上,都可以獲得不同的id。但是步長和初始值一定需要事先需要了。使用redis集群也可以方式單點故障的問題。

另外,比較適合使用redis來生成每天從0開始的流水號。比如訂單號=日期+當日自增長號。可以每天在redis中生成乙個key,使用incr進行累加。

優點:1)不依賴於資料庫,靈活方便,且效能優於資料庫。

2)數字id天然排序,對分頁或者需要排序的結果很有幫助。

缺點:1)如果系統中沒有redis,還需要引入新的元件,增加系統複雜度。

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

twitter的snowflake演算法

snowflake是twitter開源的分布式id生成演算法,結果是乙個long型的id。其核心思想是:使用41bit作為毫秒數,10bit作為機器的id(5個bit是資料中心,5個bit的機器id),12bit作為毫秒內的流水號(意味著每個節點在每毫秒可以產生 4096 個 id),最後還有乙個符號位,永遠是0。具體實現的**可以參看

c#**如下:

///

/// from:

/// an object that generates ids.

/// this is broken into a separate class in case

/// we ever want to support multiple worker threads

/// per process

///

public class idworker

if (datacenterid > maxdatacenterid || datacenterid < 0)

this.workerid = workerid;

this.datacenterid = datacenterid;

}public long nextid()

if (lasttimestamp == timestamp)

}else

lasttimestamp = timestamp;

return ((timestamp - twepoch) << (int)timestampleftshift) | (datacenterid << (int)datacenteridshift) | (workerid << (int)workeridshift) | sequence;}}

protected long tilnextmillis(long lasttimestamp)

return timestamp;

}protected long timegen()

}測試**如下:

private static void testidworker()

catch (exception e)

console.writeline("done");

}private static void dotestidwoker(idworker idworker, hashsetset)

thread.sleep(1);

}}snowflake演算法可以根據自身專案的需要進行一定的修改。比如估算未來的資料中心個數,每個資料中心的機器數以及統一毫秒可以能的併發數來調整在演算法中所需要的bit數。

優點:1)不依賴於資料庫,靈活方便,且效能優於資料庫。

2)id按照時間在單機上是遞增的。

缺點:1)在單機上是遞增的,但是由於涉及到分布式環境,每台機器上的時鐘不可能完全同步,也許有時候也會出現不是全域性遞增的情況。

利用zookeeper生成唯一id

zookeeper主要通過其znode資料版本來生成序列號,可以生成32位和64位的資料版本號,客戶端可以使用這個版本號來作為唯一的序列號。很少會使用zookeeper來生成唯一id。主要是由於需要依賴zookeeper,並且是多步調用api,如果在競爭較大的情況下,需要考慮使用分布式鎖。因此,效能在高併發的分布式環境下,也不甚理想。

mongodb的objectid

mongodb的objectid和snowflake演算法類似。它設計成輕量型的,不同的機器都能用全域性唯一的同種方法方便地生成它。mongodb 從一開始就設計用來作為分布式資料庫,處理多個節點是乙個核心要求。使其在分片環境中要容易生成得多。

其格式如下:

前4 個位元組是從標準紀元開始的時間戳,單位為秒。時間戳,與隨後的5 個位元組組合起來,提供了秒級別的唯一性。由於時間戳在前,這意味著objectid 大致會按照插入的順序排列。這對於某些方面很有用,如將其作為索引提高效率。這4 個位元組也隱含了文件建立的時間。絕大多數客戶端類庫都會公開乙個方法從objectid 獲取這個資訊。接下來的3 位元組是所在主機的唯一識別符號。通常是機器主機名的雜湊值。這樣就可以確保不同主機生成不同的objectid,不產生衝突。為了確保在同一臺機器上併發的多個程序產生的objectid 是唯一的,接下來的兩位元組來自產生objectid 的程序識別符號(pid)。前9 位元組保證了同一秒鐘不同機器不同程序產生的objectid 是唯一的。後3 位元組就是乙個自動增加的計數器,確保相同程序同一秒產生的objectid 也是不一樣的。同一秒鐘最多允許每個程序擁有2563(16 777 216)個不同的objectid。

分布式ID生成方案

系統唯一id是設計乙個系統的時候常常會遇到的問題,也常常為這個問題而糾結。生成id的方法有很多,適應不同的場景 需求以及效能要求。所以有些比較複雜的系統會有多個id生成的策略。1 全域性唯一性 不能出現重複的id號,既然是唯一標識,這是最基本的要求 2 粗略有序 如果在分布式環境中做到完全有序,需要...

分布式全域性ID生成方案

1 背景 分布式架構下,唯一序列號生成是我們在設計乙個系統,尤其是資料庫使用分庫分表的時候常常會遇見的問題。當分成若干sharding表後,如何能夠快速拿到乙個唯一序列號,是經常遇到的問題。在網際網路的業務系統中,涉及到各種各樣的id,如在支付系統中就會有支付id 退款id等。那一般生成id都有哪些...

分布式系統唯一ID生成方案彙總

前言 系統唯一id是我們在設計乙個系統的時候常常會遇見的問題,也常常為這個問題而糾結。生成id的方法有很多,適應不同的場景 需求以及效能要求。所以有些比較複雜的系統會有多個id生成的策略。下面就介紹一些常見的id生成策略。一 資料庫自增長序列或字段 最常見的方式。利用資料庫,全資料庫唯一。優點 簡單...