雪花算法中超級好用的ID生成工具

雪花算法裏最好用的主鍵ID生成器

技術支持

開源地址1:https://github.com/yitter/idgenerator前端

開源地址2:https://gitee.com/yitter/idgeneratorgit

QQ羣:646049993github

爲何用雪花ID?

❄ 由於大廠也在用,推特、百度、美團、滴滴等等。redis

❄ 雪花ID是走向分佈式架構的墊腳石,若是隻會Guid和數據庫自增,怎敢說會分佈式系統架構。算法

❄ 雪花ID適合小項目、大項目、超級大項目。數據庫

💎 本算法介紹

❄ 這是優化的雪花算法(雪花漂移),它生成的ID更短、速度更快。緩存

❄ 支持 k8s 等容器環境自動擴容(自動註冊 WorkerId),可在單機或分佈式環境生成數字型惟一ID。安全

❄ 原生支持 C#/Java/Go/Rust/C 等語言,並提供 PHP 擴展及 Python、Node.js 多線程安全調用動態庫(FFI)。服務器

❄ 這是計算機歷史上最全面的雪花ID生成器,期待你來超越😀網絡

需求來源

💧 做爲架構設計的你,想要解決數據庫主鍵惟一的問題,特別是在分佈式系統多數據庫中。

💧 你但願數據表主鍵用最少的存儲空間,索引速度更快,Select、Insert 和 Update 更迅速。

💧 你要考慮在分庫分表(合庫合表)時,主鍵值可直接使用,並能反映業務時序。

💧 若是這樣的主鍵值太長,超過前端 js Number 類型最大值,須把 Long 型轉換爲 String 型,你會以爲有點沮喪。

💧 儘管 Guid 能自增,但佔用空間大,索引速度慢,你不想用它。

💧 應用實例可能超過50個,每一個併發請求可達10W/s。

💧 要在容器環境部署應用,支持水平復制、自動擴容。

💧 不想依賴 redis 的自增操做得到連續的主鍵ID,由於連續的ID存在業務數據安全風險。

💧 你但願系統運行 100 年以上。

傳統算法問題

❌ 生成的ID太長。

❌ 瞬時併發量不夠。

❌ 不能解決時間回撥問題。

❌ 不支持後補生成前序ID。

❌ 可能依賴外部存儲系統。

新算法特色

✔ 整形數字,隨時間單調遞增(不必定連續),長度更短,用50年都不會超過 js Number類型最大值。(默認配置)

✔ 速度更快,是傳統雪花算法的2-5倍,0.1秒可生成50萬個(基於8代低壓i7)。

✔ 支持時間回撥處理。好比服務器時間回撥1秒,本算法能自動適應生成臨界時間的惟一ID。

✔ 支持手工插入新ID。當業務須要在歷史時間生成新ID時,用本算法的預留位能生成5000個每秒。

✔ 不依賴任何外部緩存和數據庫。(k8s環境下自動註冊 WorkerId 的動態庫依賴 redis)

✔ 基礎功能,開箱即用,無需配置文件、數據庫鏈接等。

性能數據

(參數:10位自增序列,1000次漂移最大值)

連續請求量 5K 5W 50W
傳統雪花算法 0.0045s 0.053s 0.556s
雪花漂移算法 0.0015s 0.012s 0.113s

💍 極致性能:500W/s~3000W/s。(全部測試數據均基於8代低壓i7計算)

如何處理時間回撥

🔶 當發生系統時間回撥時,算法採用過去時序的預留序數生成新的ID。

🔶 回撥生成的ID序號,默認靠前,也能夠調整爲靠後。

🔶 容許時間回撥至本算法預設基數(參數可調)。

💎 ID組成

  • 本算法生成的ID由3部分組成(沿用雪花算法定義):
  • +-------------------------+--------------+----------+
  • | 1.相對基礎時間的時間差 | 2.WorkerId | 3.序列數 |
  • +-------------------------+--------------+----------+
  • 第1部分,時間差,是生成ID時的系統時間減去 BaseTime 的總時間差(毫秒單位)。
  • 第2部分,WorkerId,是區分不一樣機器或不一樣應用的惟一ID,最大值由 WorkerIdBitLength(默認6)限定。
  • 第3部分,序列數,是每毫秒下的序列數,由參數中的 SeqBitLength(默認6)限定。

💎 ID示例

🟣 本算法生成的 ID ,是一串整數,最多8字節。如下是基於默認配置生成的ID:

129053495681099        (本算法運行1年)
387750301904971        (運行3年)
646093214093387        (運行5年)
1292658282840139       (運行10年)
9007199254740992       (js Number 最大值)
165399880288699493     (普通雪花算法生成的ID)

🟣 本算法生成的 ID 值,是 js Number 最大值的 1%-10%,是普通雪花算法值的千分之一,而計算能力卻超過普通雪花算法。

🟣 js Number 類型最大數值:9007199254740992,本算法在保持併發性能(5W+/0.01s)和最大64個 WorkerId(6bit)的同時,能用70年纔到 js Number Max 值。

長度估算

💍 每增長 1位 WorkerIdBitLength 或 SeqBitLength,生成的ID數字值將會乘以2(基礎長度可參考前一節「ID示例」),反之則除以2。

能用多久

🔵 在默認配置下,ID可用 71000 年不重複。

🔵 在支持 1024 個工做節點時,ID可用 4480 年不重複。

🔵 在支持 4096 個工做節點時,ID可用 1120 年不重複。

💎 參數設置

WorkerIdBitLength,機器碼位長,決定 WorkerId 的最大值,默認值6,取值範圍 [1, 19],實際上有些語言採用 無符號 ushort (uint16) 類型接收該參數,因此最大值是16,若是是採用 有符號 short (int16),則最大值爲15。

WorkerId,機器碼,最重要參數,無默認值,必須 全局惟一,必須 程序設定,缺省條件(WorkerIdBitLength取默認值)時最大值63,理論最大值 2^WorkerIdBitLength-1(不一樣實現語言可能會限定在 65535 或 32767,原理同 WorkerIdBitLength 規則)。不一樣機器或不一樣應用實例 不能相同,你可經過應用程序配置該值,也可經過調用外部服務獲取值。針對自動註冊WorkerId需求,本算法提供默認實現:經過 redis 自動註冊 WorkerId 的動態庫,詳見「Tools\AutoRegisterWorkerId」。

SeqBitLength,序列數位長,默認值6,取值範圍 [3, 21](建議不小於4),決定每毫秒基礎生成的ID個數。規則要求:WorkerIdBitLength + SeqBitLength 不超過 22。

MinSeqNumber,最小序列數,默認值5,取值範圍 [5, MaxSeqNumber],每毫秒的前5個序列數對應編號0-4是保留位,其中1-4是時間回撥相應預留位,0是手工新值預留位。

MaxSeqNumber,最大序列數,設置範圍 [MinSeqNumber, 2^SeqBitLength-1],默認值0,真實最大序列數取最大值(2^SeqBitLength-1),不爲0時,取其爲真實最大序列數,通常無需設置,除非多機共享WorkerId分段生成ID(此時還要正確設置最小序列數)。

💎 常規集成

1️⃣ 用單例模式調用。外部集成方使用更多的實例並行調用本算法,不會增長ID產出效能,由於本算法採用單線程模式生成ID。

2️⃣ 指定惟一的 WorkerId。必須由外部系統確保 WorkerId 的全局惟一性,並賦值給本算法入口方法。

3️⃣ 單機多實例部署時使用不一樣 WorkerId。並不是全部實現都支持跨進程的併發惟一,保險起見,在同一主機上部署多應用實例時,請確保各 WorkerId 惟一。

4️⃣ 異常處理。算法會拋出全部 Exception,外部系統應 catch 異常並作好應對處理,以避免引起更大的系統崩潰。

5️⃣ 認真理解 IdGeneratorOptions 的定義,這對集成和使用本算法有幫助。

6️⃣ 使用雪花漂移算法。雖然代碼裏包含了傳統雪花算法的定義,而且你能夠在入口處指定(Method=2)來啓用傳統算法,但仍建議你使用雪花漂移算法(Method=1,默認的),畢竟它具備更好的伸縮力和更高的性能。

7️⃣ 不要修改核心算法。本算法內部參數較多,邏輯較爲複雜,在你還沒有掌握核心邏輯時,請勿嘗試修改核心代碼且用於生產環境,除非經過大量細緻、科學的測試驗證。

💎 配置變動

配置變動指是系統運行一段時間後,再變動運行參數(IdGeneratorOptions選項值),請注意:

🔴 1.最重要的一條原則是:BaseTime 只能往前(比老值更小、距離如今更遠)賦值,緣由是日後賦值極大可能產生相同的時間戳。[不推薦在系統運行以後調整 BaseTime]

🔴 2.任什麼時候候增長 WorkerIdBitLength 或 SeqBitLength,都是能夠的,可是慎用 「減少」的操做,由於這可能致使在將來某天生成的 ID 與過去老配置時相同。[容許在系統運行以後增長任何一個 BitLength 值]

🔴 3.若是必須減少 WorkerIdBitLength 或 SeqBitLength 其中的一項,必定要知足一個條件:新的兩個 BitLength 之和要大於 老的值之和。[不推薦在運行以後縮小任何一個 BitLength 值]

🔴 4.上述3條規則,並未在本算法內作邏輯控制,集成方應根據上述規則作好影響評估,確認無誤後,再實施配置變動。

自動註冊WorkerId

🔍 惟一ID生成器,依賴WorkerId,當業務服務須要水平無差異複製時,就要求它能自動註冊全局惟一WorkerId,而後才能根據它生產惟一ID。

🔍 本算法提供一個開源動態庫(go語言實現),能在容器 k8s(或其它容器化集羣) 環境下,經過 redis 自動註冊 WorkerId。

🔍 經過redis註冊WorkerId,並非惟一的方法。你也能夠本身開發一個配置中心服務,各個應用服務啓動時,經過配置中心獲取惟一 WorkerId。

🔍 固然,若是你的服務不須要自動擴展,你就沒必要自動註冊WorkerId,而是爲每一個應用手工設定一個惟一值。

自動註冊流程圖

圖片連接:https://gitee.com/yitter/idgenerator/blob/master/Tools/AutoRegisterWorkerId/regprocess.jpg

源碼路徑:/Go/source/regworkerid/reghelper.go

動態庫下載

下載連接:https://gitee.com/yitter/idgenerator/attach_files/662372/download/regworkerid_lib_v1.0.zip

動態庫接口定義

// 註冊一個 WorkerId,會先註銷全部本機已註冊的記錄
// ip: redis 服務器地址
// port: redis 端口
// password: redis 訪問密碼,可爲空字符串「」
// maxWorkerId: 最大 WorkerId
extern GoInt32 RegisterOne(char* ip, GoInt32 port, char* password, GoInt32 maxWorkerId);

// 註銷本機已註冊的 WorkerId
extern void UnRegister();

// 檢查本地WorkerId是否有效(0-有效,其它-無效)
extern GoInt32 Validate(GoInt32 workerId);

已實現的語言

語言 github gitee
🌲 C# 查看示例 查看示例
🌲 Java 查看示例 查看示例
🌲 Go 查看示例 查看示例
🌲 Rust 查看示例 查看示例
🌲 C 查看示例 查看示例
🌲 C (PHP擴展) 查看示例 查看示例
🌲 V 查看示例 查看示例
🌲 D 查看示例 查看示例

爲何不用大廠的?

❄ 首先,大廠們不但本身用雪花ID,並且還開源:百度 | 美團 | 滴滴 | 雪花ID鼻祖-推特

❄ 然而,大廠的雪花算法分爲「經典算法」和「號段算法」兩種,其中「號段算法」依賴網絡或外部存儲系統,不適合「非大廠」,且存在沒法反應業務時序的缺點。

❄ 至於其「經典算法」,在「ID長度和生成性能」方面,未作過優化,而這正式本算法——雪花漂移算法的核心所在。

相關文章
相關標籤/搜索