雪花演算法和UUID
UUID
UUID是一種唯一且不需要中央協調的ID,它使用某種規則建立ID,而不是某種中心化的自增方式,使得其成為建立成本最低的ID型別。
到目前為止UUID一共有5個實現版本
-
版本1: 按照 UUID 定義的每個欄位的意義來實現,使用的變數因子是時間戳+時鐘序列+節點資訊(Mac地址),考的最多的版本
-
版本2:基本和1一致,資訊很少,可忽略
-
版本3:基本name和namespace的hash實現變數因子,使用MD5進行hash,不是隨機生成
-
版本4:使用隨機或者偽隨機實現變數因子,不具備單調性,使用最廣泛
-
版本5:基本name和namespace的hash實現變數因子,使用sha1進行hash,不是隨機生成
這些版本的結構基本都是一致的,只是在版本1的基礎上變化了變數因子
UUID長度128位元,換算為16進位制數就是有32個16進位制陣列成,中間用4個-分割,所以一共有36個字元,按照8-4-4-4-4-12的的順序進行分割。
組成它的變數因子一共有三個,Timestamp時間戳、Clock Sequence時鐘序列,node節點資訊。
Timestamp時間戳:60bit 15個數
這15個數分佈在前3個組成中,分別是時間戳低位8個、時間戳中位4個、時間戳高位3個,第三個部分的第一位是UUID版本欄位,佔4個位元組,所以可以有16個版本號
Clock Sequence時鐘序列:14bit 三個半數,最左邊的2bit是保留位
時鐘序列一般用於時間調整時的唯一性保證,當時間調整,或者 nodeId 變化的時候,直接使用一個隨機數,或者,在原先的Clock Sequence值上面自增加一也是可以的。
保留位用於未來的擴充套件以及保持UUID的標準相容性,確保UUID的格式能夠適應將來的需求而不影響現有的實現。
Node節點資訊:12個數,一般是MAC地址或者隨機數生成
基於name和namespace的hash結構生成是什麼意思?
- Name: 是物件的名稱或識別符號。比如,在 Kubernetes 中,Pod 的名稱就是一個典型的
name
。 - Namespace: 是一個名稱空間,用於將不同作用域內的物件區分開來。例如,兩個相同名稱的 Pod 可以存在於不同的名稱空間,從而不衝突。
在 UUID v3 和 UUID v5 中,name
和 namespace
是生成 UUID 的關鍵輸入,它們並不是自動變化的,而是由開發者根據具體應用場景指定的。每次生成 UUID 時,使用相同的 name
和 namespace
組合,會得到相同的 UUID。
雪花演算法
雪花演算法生成的64位ID由以下幾部分組成:
第一位(符號位):由於ID都是正整數,所以第一位始終為0。
時間戳(41位):記錄時間戳的差值(相對於某個固定時間點),單位是毫秒。41位時間戳可以使用69年(從1970年開始,可用至2039年)。
工作機器id(10位):用於標識不同的工作機器(如不同的伺服器例項),支援在同一資料中心內部署最多1024臺機器。
如果存在跨機房部署的情況下可以把這10個bit位,拆分成兩個5bit,前5個bit表示機房id,後面5個表示機器的id
序列號(12位):用於在同一毫秒內產生不同的ID,支援每個工作機器在同一毫秒內產生最多4096個ID。
時鐘回撥和時鐘漂移
時鐘回撥是指系統時間被人為或自動地調整到過去的某個時間點。
時鐘漂移是指由於硬體本身的物理特性,系統時鐘的計時速率可能並不完全準確,隨著時間推移,會逐漸偏離標準時間。
雪花演算法怎麼解決時鐘回撥和時鐘漂移?
-
時間強依賴變成弱依賴,只有第一次演算法啟動的時候獲取時間戳,之後都是演算法增加時間戳,而不是依賴於系統時間。這種方式可以避免一毫秒只能生成4096個ID的弊端。仍然會有ID衝突,例如,一小時內獲取一千萬條ID,這個實際上是獲取了未來的ID,這樣如果伺服器重啟,獲取了舊的時間戳,就會出現ID重複,解決方案是儲存當前使用到的時間戳,下一次啟動時獲取。
-
透過機器ID或者序列號進行補償,可以增加機器ID的部分或者增加序列號的部分,UUID也是這種方案。
-
阻塞等待時間追趕(兜底策略)。