常見的分布式唯一ID方案

2022-05-17 10:01:21 字數 2705 閱讀 2870

最近看乙個新系統,發現裡面有很多場景用到唯一id,便蒐羅了一下常見的方案。

對於分布式id,需要滿足下面的基本要求

全域性唯一

趨勢遞增

uuid(universally unique identifier)全域性唯一識別符號,定義為乙個字串主鍵,採用32位數字組成,編碼採用16進製制,定義了在時間和空間都完全惟一的系統資訊。

uuid的編碼規則:

1~8位採用系統時間,在系統時間上精確到毫秒級保證時間上的惟一性;

9~16位採用底層的ip位址,在伺服器集群中的惟一性;

17~24位採用當前物件的hashcode值,在乙個內部物件上的惟一性;

25~32位採用呼叫方法的乙個隨機數,在乙個物件內的毫秒級的惟一性。

通過以上4種策略可以保證惟一性。在系統中需要用到隨機數的地方都可以考慮採用uuid演算法。

無序,沒有自增趨勢,作為主鍵插入效率低下(如mysql)

過長,浪費儲存空間

無法儲存業務邏輯,可讀性差,當然如果你的id沒有長度限制,可以通過拼接字首/字尾來增加資訊

可以引入中心協調器類,通過該系統自帶的特性來完成id的生成和分配。

don't say so match,大家應該都用過,通過db的auto_increment自增主鍵來控制id的唯一以及有序,使用簡單。當然缺點也是明顯的,依賴db存在單點問題,當然可以通過主從模式來解決單點問題。

網上還有有人介紹了自增主鍵的另一種模式,如下

引入多例項,為每個例項設定初始值以及固定的步長來降低單點的風險,以及分攤db壓力。當然只是降低,單點問題還是存在的,同時還不容易擴容,也需要客戶端做支援。對於趨勢遞增則需要id服務來維持,它需要輪訓訪問後端的各個db例項,以維持趨勢遞增的特性。

redis提供了incr命令可以實現id的原子性自增,能夠達到類似db的auto_increment的效果。使用redis需要注意持久化的問題,避免redis重啟後資料丟失導致id重複。

zookeeper自帶生成順序節點的功能,可以使用其生成順序節點的編號來作為id。客戶端建立完節點後,通過解析返回的節點名來獲得當前分配的id。

中心協調器類其實都差不多,將id的生成轉到中心協調器上。

資料庫號段的方式如下:

涉及的表結構如下:

type欄位用來區分不同的業務,隔離不同業務之間的相互影響;max_id欄位則表示當前業務型別已經分配的最大id值,下一次分配則從該值開始;step為步長;state用來做鎖控制,這裡用的是樂觀鎖,也可以不用該欄位,改為行鎖(select ... for update)。

以biztype1為例,資料庫中記錄著biztype1的下乙個id起始值3000,以及對應的步長1000。當應用啟動後首次使用時,嘗試去獲取biztype1這條記錄的鎖,獲取到鎖的應用讀取max_id和step的值,同步更新到記憶體,然後將max_id的值加上步長後更新回表中,這個值便是下乙個id的起始值。當應用例項記憶體中的步長沒有消耗完前,直接通過應用內部自己自增返回id,避免頻繁請求db。當應用消耗完後則再次訪問db同步更新max_id和step,反覆迴圈下去。

開頭講到的最近接觸的新系統用的就是號段的方式來生成唯一id,但它不是用樂觀鎖的方式而是用行鎖。測試環境給的步長比較小,剛好測試同學在做壓測造資料的時候併發開的大,導致搶鎖鎖頻繁拋異常了。當然如果使用樂觀鎖也會存在飢餓的情況,會導致一直獲取不到鎖而一直忙等。

看完上面的過程,其實核心點在於有個第三方系統來提供鎖和儲存以及應用端的配合,所以其實不用db也可以實現該功能。

該演算法使用乙個64 bit的整型資料,包括

首位不用的1個bit(最高位是標識位,為1表示為負數,不使用)

41個bit的毫秒級時間(41位的長度可以使用69年),

10個bit的工作機器id,包括5個bit的datacenterid和5個bit的workerid(10位的長度最多支援部署1024個節點)

12個bit的毫秒內的計數(12位的計數順序號支援每個節點每毫秒產生4096個id序號)

一共加起來剛好64位,為乙個long型。

snowflake演算法核心把時間戳,工作機器id,序列號組合在一起。整體上按照時間自增排序,並且整個分布式系統內不會產生id碰撞(由datacenter和機器id作區分),並且效率較高,經測試,snowflake每秒能夠產生26萬id左右,完全滿足需要。

snowflake演算法中41個bit的時間戳完全依賴於時間的,如果有時鐘回撥的情況發生,則會生成重複的id。時鐘回撥涉及兩種情況

例項停機→時鐘回撥→例項重啟→計算id

例項執行中→時鐘回撥→計算id

對於時間回撥,網上給出了很多處理方法,包括:

如果發現有時鐘回撥,時間很短比如5毫秒,就等待,然後再生成;或者就直接報錯,交給業務層去處理

可以找2bit位作為時鐘回撥位,發現有時鐘回撥就將回撥位加1,達到最大位後再從0開始進行迴圈

分布式唯一ID方案

背景 在複雜的分布式系統中,往往需要對大量的資料和訊息進行唯一標識。如對大量的訂單做分庫分表後,需要有乙個唯一的id來標識一條資料或訊息,資料庫的自增id顯然不能滿足需求。業務系統對分布式唯一id的要求 全域性唯一性,不能重複 趨勢遞增,在mysql innodb引擎中使用的是聚集索引,由於多數rd...

js生成唯一id 常見的分布式系統唯一ID生成方案

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

分布式唯一ID的生成方案

不能出現重複的id,這是最基本的要求。有利於關聯式資料庫索引效能。既然是服務於分布式系統,為多個服務提供id服務,訪問壓力一定很大,所以需要保證高可用。如果id是有規律的,就容易被惡意操作,在一些場景下需要id無規則。核心思想是結合機器的網絡卡 當地時間 乙個隨機數來生成。優點 缺點 利用資料庫自增...