分佈式全局惟一ID生成策略

「惟一ID」在應用程序中是一個很常見的需求,它用於惟一標識一個業務對象、一個資源、或者一個消息等等。在數據庫中,惟一ID通常是用來作爲一個數據的主鍵。看過前面介紹MySQL索引原理的文章的朋友應該知道,主鍵對於數據庫的重要性不言而喻。算法

在單機場景下,要獲得一個全局惟一的ID是很是容易的,你可使用數據庫的自增功能數據庫

可是若是在分佈式的場景下,想要構建構建一個全局惟一的ID就有些不同。由於分佈式系統通常是高併發場景,那天然不適合使用單機數據庫的自增功能了。若是你的技術選型剛好是MySQL這樣的「非分佈式數據庫」,那就得參考一下業界常見的分佈式全局惟一ID生成策略了。緩存

UUID

UUID全稱是Universally Unique Identifier,翻譯過來叫通用惟一識別碼。標準型式包含32個16進制數字,以連字號分爲五段,形式爲8-4-4-4-12的36個字符,示例:9628f6e9-70ca-45aa-9f7c-77afe0d26e05,到目前爲止業界一共有5種方式生成UUID,詳情見IETF發佈的UUID規範《A Universally Unique IDentifier (UUID) URN Namespace》,分別稱爲UUID的5個版本。服務器

在JDK自帶的UUID類能夠產生版本3和版本4的UUID。因此這裏簡單介紹一下版本3和版本4的UUID的生成方式。數據結構

  • UUID版本3:經過計算name和namespace的MD5散列值獲得。
  • UUID版本4:根據隨機數,或者僞隨機數生成UUID。這種UUID產生重複的機率是能夠計算出來的,可是重複的可能性能夠忽略不計,所以該版本也是被常用的版本。

image.png

也有在線生成UUID的網站,若是你的項目上用到了UUID,能夠用來生成臨時的測試數據。www.uuidgenerator.net/併發

UUID的優點是實現起來很簡單,用JDK原生的API便可獲得。劣勢是與基於b-Tree引擎的數據庫的主鍵索引策略不太符合,不適合做爲高性能需求的場景下的數據庫主鍵。分佈式

基於Redis實現

都用分佈式了,多半要上個緩存。用緩存的話,可能會使用Redis。Redis的INCR函數在單機上是原子操做,能夠保證惟一且遞增。函數

單機Redis可能沒法支撐高併發。而若是使用Redis集羣,如何保證ID的惟一性呢?可使用步長的方式。好比有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

類snowflake方案

Twitter利用Zookeeper實現了一個全局ID生成的服務snowflake。其生成ID的數據結構以下圖所示:

snowflake格式

共64位,正好對應Java中的long型,第一個符號位不用,而後41位用於表示時間戳。後續10位用來表示節點的id,若是是多機房節點,能夠劃分前5位用來表示機房id,後5位用來表示每一個機房下的機器的id。最後12位用來表示序列號,這樣能夠作到同一毫秒,同一機器生成多個id,12位算下來最多支持4096個。

這裏的時間戳並非當前時間的Time Stamp,而是當前時間相對於起始時間的差值。若是基於毫秒來計算的話,41位大約能夠用69年。

snowflake算法有許多變種。能夠根據本身的實際狀況調整位數的分配,好比時間戳佔42位,機器id佔9位。42位時間戳就能夠用138年等。

百度的UidGenerator和美團的Leaf都是基於snowflake的變種。

snowflake是一種比較好的生成ID方式,保證全局惟一,且支持高併發。並且是long類型的,趨勢遞增,能夠用於數據庫主鍵。還能夠根據時間來排序。

但也有其缺點,就是強依賴服務器的時鐘,若是服務器的時鐘出現回撥(好比閏秒或者NTP同步),就會致使ID重複。

美團的Leaf解決了時鐘回撥的問題,具體流程以下圖,能夠了解一下:

Leaf時鐘回撥

其餘方式

固然,還有一些其餘的ID生成方案,好比:

  • 滴滴:時間+起點編號+車牌號

  • 淘寶訂單:時間戳+用戶ID

  • 其餘電商:時間戳+下單渠道+用戶ID,有的會加上訂單第一個商品的ID。

  • MongoDB的ID:也算是類snowflake的一種。經過「時間+機器碼+pid+inc」共12個字節,4+3+2+3的方式最終標識成一個24長度的十六進制字符。

總結

若是不用於數據庫主鍵,建議直接用UUID。

若是想要用來作數據庫主鍵,又沒有使用分佈式數據庫(好比TiDB、MongoDB等),能夠考慮使用snowflake算法,建議使用美團的Leaf。

數據庫中間件sharding-jdbc的分佈式ID採用twitter開源的snowflake算法,不須要依賴任何第三方組件,這樣其擴展性和維護性獲得最大的簡化;可是snowflake算法的缺陷(強依賴時間,若是時鐘回撥,就會生成重複的ID),sharding-jdbc沒有給出解決方案,若是用戶想要強化,須要自行擴展。

認真寫文章,用心作分享。

我的網站:yasinshaw.com

公衆號:xy的技術圈

相關文章
相關標籤/搜索