五分鐘技術趣談| 分佈式UUID的生成策略及應用場景淺析

2023.07.15

五分鐘技術趣談| 分佈式UUID的生成策略及應用場景淺析


UUID是國際標準化組織(ISO)提出的一個概念。UUID用來識別屬性類型,在所有空間和時間上被視為唯一的標識。本文將從UUID的構成方式、現行版本、生成策略、應用案例等方面作介紹。

Part 01

什麼是UUID 

UUID全稱Universal Unique Identifier是一串128位數字碼,用於唯一識別網絡對像或者事件。由於其獨特的生成機制和使用場景,UUID可以確保全局唯一性,避免重複。UUID廣泛應用於各種需要唯一識別的場景,例如數據庫主鍵、系統實例ID, 識別生命週期短暫的藍牙配置文件和對像等。

UUID是類似於GUID的術語,最初由微軟引入的GUID實際上是UUID的一種變體,在RFC 4122規範中將這兩個術語定義為同義詞。隨後,開放軟件基金會(OSF)對UUID進行了標準化,使其成為分佈式計算網絡中的重要組成部分,衍生出的各個UUID版本都遵循RFC 4122規範。

Part 02

UUID的構成方式 

但如果計UUID通常通過特定算法生成,例如基於時間戳或網絡地址等。UUID通過特定的組合排列方式確保其唯一性,由32個16進制數字(包括數字0到9和字母A到F)和4個連字符構成。每個連字符的字符數是8-4-4-4-12,其中最後4位或者N位表示格式和編碼:

圖片

UUID也可以用十進製或者二進制格式表示:

圖片

傳統的UUID大致分成3種變體:

➤ 變體0:為了兼容80年代未過時的阿波羅網絡計算系統而保留,它的結構與目前使用的version 1相似。

➤ 變體1:目前主要使用的變體,在Internet工程文檔規範中被定義為RFC 4122/DCE 1.1 UUID或Leach-Salz UUID,例如微軟的GUID就是UUID的變體1。

➤ 變體2:為了兼容微軟後續發展而保留,儘管現有的微軟GUID是UUID的變體1,但早期Windows平台使用的是變體2。變體1和變體2在N位位置的比特數字不同,例如變體1使用2位比特位,而變體2使用3位比特位。

Part 03

UUID的現行版本

現有的UUID主要是基於變體1衍生出來的,由5個不同版本組成,不同版本的UUID生成方式有所區別,具體包括:

➢ Version1:基於時間戳和節點生成的UUID。它使用當前時間和計算機的MAC地址來生成唯一標識符。這個版本的UUID保證了全局唯一性和時間排序性,但在某些情況下可能存在安全性和隱私問題。

➢ Version2:基於DCE安全標識符(DCE Security Identifier)生成的UUID。這個版本的UUID將標識符的角色和權限信息編碼到UUID中,使其能夠表示用戶、組和ACL(訪問控制列表)。然而,這個版本的UUID並不常見,也沒有得到廣泛支持。

➢ Version3:基於名稱和命名空間生成的UUID。它使用MD5散列函數對名稱和命名空間進行處理,生成唯一的標識符。這個版本的UUID可用於標識命名空間中的對象,如URL、域名等。

➢ Version4:基於隨機數生成的UUID。這個版本的UUID使用隨機數生成算法生成,因此具有很高的隨機性和唯一性。它是目前最常用的UUID版本,廣泛應用於各種領域。

➢ Version5:基於名稱和命名空間生成的UUID。它與Version 3相似,但使用的是SHA-1散列函數,提供更強的散列算法。這個版本的UUID也可用於標識命名空間中的對象。

Part 04

現有UID的生成策略 

4.1 Mysql生成ID

Mysql使用主鍵auto_increment方式生成ID,ID之間的步長固定,但可以自定義步長。這種方式簡單易用,可以保證ID的遞增性和唯一性,但是存在單點故障和數據一致性問題、在擴展性方面也存在一定的挑戰。

4.2 MongoDB生成ID

MongoDB生成的UUID是由12字節十六進制數字組成,具體組成:4字節--以秒為單位的時間戳,3字節--機器標識符,2字節--進程ID,3字節--計數器(從一個隨機值開始)。比傳統的UUID短,但比MYSQL自動增量字段(64位Bigint值)長。

4.3 Redis生成ID

Redis通常使用原子操作INCR或INCRBY實現ID生成。如果是Redis集群可以設置ID初始值並自定義每個節點ID的步長。由於Redis是單線程模型,可以保證生成的ID具備唯一性。

4.4 Zookeeper生成ID

Zookeeper主要通過ZNODE數據版本生成ID,此ID通常是32位或者64位字符串構成,客戶端可以使用該ID作為UID使用。由於需要強依賴Zookeeper,在高並發的場景多的情況下很少考慮使用這種方式。

Part 05

UUID的應用案例分析 

5.1 Twitter生成UUID

Twitter使用雪花算法作為專業服務來統一生成64位唯一標識符,用於分佈式系統中的對象標識,例如推特、直接消息、列表等。這些ID是基於時間的的唯一無符號64位整數,完整的ID定義主要組成方式如下:

  • 41位--時間戳以毫秒為單位(相對於任何自定義紀元,通常可以使用69年)
  • 10位--已配置的機器/節點/分片ID
  • 12位--序列號(每台機器的本地計算器,每4096個值後設置為0)
  • 1位--額外保留位,一般被設置為0來確保總數為正值

圖片圖片

按著這種方法構成的UID不僅提高可用性,因為使用時間戳為首部分,還可以根據時間進行排序。默認情況下,雪花算法生成一個64位的無符號長整型,也就是長度為19的ID。有時具體項目中可能不需要這麼長,也可以根據自身需要修改該算法。

5.2 百度生成UUID

百度基於雪花算法改進生成UID,對UID的bit位進行調整,將時間戳部分修改為28位,用於表示當前時間與初始上線生成的時間的時間差(單位為秒),其中初始時間可以手工配置。使用22位表示工作節點ID,實例啟動的時候生成分佈式ID,寫入數據庫中得到的自增長序列值。使用13位序列號來解決時間回撥等問題,如果當前時間和上一次是時間相同則序列自增,超過閾值則自旋。

圖片圖片

5.3 美團生成UUID

美團基於雪花算法改進,使用“1+41+5+5+12”的方式構成UID,在原雪花算法的基礎上,使用5位bit代表機器ID,5位bit代表機房ID,12位序列號代表自增值,由於集群較大,基於Zookeeper組件特性配置機器ID。對於時間回撥問題的解決方案,設定閾值5毫秒,回撥時間小於5毫秒則等待回撥後重新生成新的UID,超過閾值則拋出異常。

圖片圖片

其他大型互聯網公司生成UID的方案,大部分都是基於Twitter的雪花算法進行改進,其中滴滴使用“時間戳+起點編號+車牌號”生成相應的UID,淘寶訂單則使用“時間戳+用戶ID”生成,滴滴則在美團的方案上將號段加載到內存中,同時支持多個主節點模式。微信的UID生成則主要綁定用戶序列號,採用步進式持久化和分號段共享存儲的實現方式。

Part 06

省級寬帶電視會員管理平台的應用實踐 

省級寬帶電視會員管理平台主要管理各省寬帶電視的會員用戶,是一個大型分佈式平台,服務器跨省分佈,數量眾多,存在時鐘回退問題。因此,本平台在雪花算法基礎上進行改進,增加時間線的概念,可以同時支持多條時間線並行,很好地解決了時鐘回退問題。具體方案如下:

圖片

調整2位bit代表時間線,最多支持4條時間線,所有時間線設定統一初始時間,指定一條時間線為統一時間線,根據該時間線生成相應的ID,推進時間進度。機器發生時鐘回撥時,當回撥時間間隔大於設定的閾值,切換到另一條時間線繼續生成ID。