分佈式ID生成器Ray

背景

在應用程序中,常常須要全局惟一的ID做爲數據庫主鍵。git

咱們須要什麼樣的ID生成器

  • 高性能 -> 1.生成性能高 2.插入性能高 3.索引性能高
  • 高可用 -> 1.依賴中間件要少 2.避免單節點問題
  • 不重複 -> 1.集羣內全局不重複
  • 易使用 -> 1.接入簡單 2.零學習成本
  • 語義性 -> 1.ID帶有一些其它信息

如何知足這幾點要求

  • 生成性能高 -> 大多數時間爲內存分配,減小IO,減小鎖
  • 插入性能高 -> 全局遞增,避免頁分裂
  • 索引性能高 -> 數值類型
  • 全局不重複 -> 分佈式一致性
  • 服務高可用 -> 減小依賴中間件,減小中間件交互時間

總結特性

  • 全局遞增
  • 數字類型
  • 全局惟一
  • 無鎖併發
  • 內存分配
  • 單機生成(大多數時間)

SnowFlake

Twitter把存儲系統從MySQL遷移到Cassandra,由於Cassandra沒有順序ID生成機制,因此開發了這樣一套全局惟一ID生成服務。Ray的基本思想來自於SnowFlake,解決了一些SnowFlake中存在的一些問題github

如何保證單機遞增不重複

最簡單的思路:時間戳+序列號 僞代碼:數據庫

If 當前時間 > 上次ID生成時間 -> 當前時間+序列號0
If 當前時間 = 上次ID生成時間 -> 當前時間 + 上次序列號+1
If 當前時間 < 上次ID生成時間 -> 是否存在這種狀況
複製代碼

如何保證全局不重複

如何判斷兩個ID是重複的?咱們認爲兩個ID每一位都是重複的則兩個ID重複。bash

兩個重複的數值若是分別拼接上不一樣的數值,則最終這兩個數值不相同,如:併發

1111和1111,分別拼上1和2分佈式

則1111-1和1111-2是不相同的性能

以前咱們在經過時間戳+序列號實現單機內不重複學習

那麼咱們只須要保證單機內不重複的ID + 不重複的實例ID(workId)就能保證最終生成的ID不重複spa

如何保證workId不重複

這是一個分佈式一致性問題設計

這個可使用分佈式鎖實現每一個實例獨佔一個workId

而且這僅在啓動時和續約時會依賴中間件

即便依賴的中間件中間暫時不可用,只是新的服務不能使用,舊的正常

階段性總結

  • 全局遞增(時間戳自帶全局遞增)-> 插入,索引高性能
  • 內存分配(分配時無IO)-> 生成高性能
  • 單機生成(僅啓動時強依賴中間件)-> 高可用

SnowFlake存在的問題

時鐘偏斜問題

現代計算機至少有兩種不一樣的時鐘:時鐘和單調鍾。儘管它們都衡量時間,但區分這二者很重要,由於它們有不一樣的目的。

時鐘

它根據某個日曆返回當前日期和時間。例如: Java中的System.currentTimeMillis()返回自epoch(1970年1月1日 午夜 UTC,格里高利曆)以來的秒數(或毫秒),根據公曆日曆,不包括閏秒。

單調鍾

適用於測量持續時間(時間間隔),例如Java中的System.nanoTime()都是單調時鐘。這個名字來源於他們保證老是前進的事實。

問題

時鐘的問題在於,雖然它們看起來簡單易用,但卻具備使人驚訝的缺陷:一天可能不會有精確的86,400秒,時鐘可能會先後跳躍,而一個節點上的時間可能與另外一個節點上的時間徹底不一樣。 若是時間往前撥咱們就沒法確保時間戳+序列號生成的ID是單機惟一的。

單位毫秒內生成數上限

SnowFlake單位毫秒內生成的ID數不能超過12位的序列位

問題總結

也就是說SnowFlake嚴重依賴於當前時間戳,而且只能處理當前時間戳大於等於上次時間戳的狀況,對於當前時間戳小於上次時間戳的狀況沒法處理。

解決時鐘偏斜問題

If 當前時間 > 上次ID生成時間 -> 當前時間+序列號0
If 當前時間 = 上次ID生成時間 -> 當前時間 + 上次序列號+1
If 當前時間 < 上次ID生成時間 ->上次ID生成時間 + 上次序列號 +1
複製代碼

時鐘偏斜,時間前跳其實就是等價於當前時間 < 上次ID生成時間

如何記錄上次ID生成時間

首先上次ID生成時間記錄在當前實例內存中 若是時鐘回撥發生在重啓時,上次ID生成時間記錄會丟 此時新實例拿到了它的workId,而且新機器的時間戳更早就會出現ID重複的狀況 因此須要後臺按期同步全局最大的時間戳到中間件,實例退出和啓動前同步時間戳

無盡的序列號

SnowFlake爲何會出現序列號只有4096位的狀況? 1.位數就那麼多,你能夠從機器位上分配 2.沒有進位的空間,只支持當前時間戳>=上次時間戳 Ray支持當前時間<上次時間 意味着4096位用完能夠往時間戳上進位,解決突發流量

Ray

Ray參考了SnowFlake的設計,解決了時鐘回調和序列號不足的問題,而且提供了更好的併發性能 Github地址:github.com/KeshawnVan/…

相關文章
相關標籤/搜索