比雪花演算法更好用的ID生成演算法(單機或分散式唯一ID)
? 演算法介紹
❄ 一個全新的雪花漂移演算法,生成的ID更短、速度更快。
❄ 核心在於縮短ID長度的同時,具有極高瞬時併發處理量(保守值 50W/0.1s)。
❄ 原生支援 C#/Java/Go/Rust/C 等語言,並由 Rust 提供 PHP、Python、Node.js、Ruby 等語言多執行緒安全呼叫庫(FFI)。如果你的應用有語言開發,基於本演算法提供的邏輯實現,整合會更簡單,邏輯會更一致。
❄ 支援 k8s 等容器化部署,自動註冊 WorkerId。
❄ 可在單機或分散式環境中生成唯一ID。
? 技術支援
開源地址1:https://gitee.com/yitter/idgenerator
開源地址2:https://github.com/yitter/idgenerator
QQ群:646049993
需求來源
? 作為架構設計的你,想要解決資料庫主鍵唯一的問題,特別是在分散式系統多資料庫的時候。
? 你希望這個主鍵是用最少的儲存空間,索引速度更快,Select、Insert 和 Update 更迅速。
? 你要考慮在分庫分表(合庫合表)時,主鍵值可直接使用,並能反映業務時序。
? 如果這樣的主鍵值太長,超過前端 JS Number 型別最大值,須把 Long 型轉換為 String 型,你會覺得有點沮喪。
? 儘管 Guid 能自增,但佔用空間大,索引速度慢,你也不想用它。
? 應用例項可能超過50個,每個併發請求可達10W/s。
? 在容器環境部署應用(水平擴充套件、自動伸縮)。
? 不想依賴 redis 的自增操作。
? 你希望系統執行 100 年以上。
傳統演算法問題
❌ 生成的ID太長。
❌ 瞬時併發量不夠。
❌ 不能解決時間回撥問題。
❌ 不支援後補生成前序ID。
❌ 依賴外部儲存系統。
新演算法特點
✔ 整形數字,隨時間單調遞增(不一定連續),長度更短,用50年都不會超過 js Number型別最大值。(預設配置 WorkerId 是6bit,自增數是6bit)
✔ 速度更快,是傳統雪花演算法的2-5倍,0.1秒可生成50萬個。(i7筆記本,預設演算法配置6bit+6bit)
✔ 支援時間回撥處理。比如伺服器時間回撥1秒,本演算法能自動適應生成臨界時間的唯一ID。
✔ 支援手工插入新ID。當業務需要在歷史時間生成新ID時,用本演算法的預留位能生成5000個每秒。
✔ 漂移時能外發通知事件。讓呼叫方確切知道演算法漂移記錄,Log併發呼叫量。
✔ 不依賴任何外部快取和資料庫。(k8s環境下自動註冊 WorkerId 的動態庫依賴 redis)
✔ 基礎功能,開箱即用,無需配置檔案、資料庫連線等。
效能資料
(引數:10位自增序列,1000次漂移最大值)
連續請求量 | 5K | 5W | 50W |
---|---|---|---|
傳統雪花演算法 | 0.0045s | 0.053s | 0.556s |
雪花漂移演算法 | 0.0015s | 0.012s | 0.113s |
效果
? js Number 型別最大數值:9007199254740992,本演算法在保持併發效能(5W+/0.01s)和最大64個 WorkerId(6bit)的同時,能用70年才到 js Number Max 值。
? 增加WorkerId位數到8bit(256節點)時,15年達到 js Number Max 值。
? 極致效能:500W/s~3000W/s。(所有測試資料均基於8代低壓i7計算。)
? 生成的ID
預設配置:
WorkerIdBitLength = 6
SeqBitLength = 6
ID示例(基於預設配置):
129053495681099 (本演算法執行1年)
387750301904971 (執行3年)
646093214093387 (執行5年)
1292658282840139 (執行10年)
9007199254740992 (js Number 最大值)
165399880288699493 (普通雪花演算法生成的ID)
本演算法生成的 ID 值,是 js Number 最大值的 1%-10%,是普通雪花演算法值的千分之一,而計算能力卻超過普通雪花演算法。
適用範圍
?小型、中型、大型需要全域性唯一Id(不用Guid)的專案。
? 分散式專案。
?不想將 Long 型轉 String 給前端用的專案。(若前端支援bigint,則可不轉型別)
如何處理時間回撥
? 當發生系統時間回撥時,演算法採用過去時序的預留序數生成新的ID。
? 預設每秒生成100個(速度可調整)。
? 回撥生成的ID序號,預設靠前,也可以調整為靠後。
? 允許時間回撥至本演算法預設基數(引數可調)。
能用多久
? 在預設配置下,ID可用 71000 年不重複。
? 在支援 1024 個工作節點時,ID可用 4480 年不重複。
? 在支援 4096 個工作節點時,ID可用 1120 年不重複。
? 以上所有工作節點,均擁有 50W/0.1s 瞬時處理速度。
預設配置
? WorkerIdBitLength=6,能支援64個 WorkerId,編號0~63。
? 可通過減少 WorkerIdBitLength 到1~4(為4時最大支援WorkerId為2^4=16個),以減少Id長度。
? SeqBitLength=6,能支援每秒併發5W請求時,平均處理速度不超過 0.005 s。(不同語言略有差別,最高效能不超過0.002s,平均不超過0.005s)
? 可通過增加 SeqBitLength,支援更高的每秒併發數。預設配置能很高效地支援每秒 5W 併發請求,若要求更高,可適當增加 SeqBitLength 到 8~16,但這將增加Id長度。
整合建議
? 常規整合
1️⃣ 用單例模式呼叫。外部整合方使用更多的例項並行呼叫本演算法,不會增加ID產出效能,因為本演算法採用單執行緒模式生成ID。
2️⃣ 指定唯一的 WorkerId。必須由外部系統確保 WorkerId 的全域性唯一性,並賦值給本演算法入口方法。
3️⃣ 單機多例項部署時使用不同 WorkerId。並非所有實現都支援跨程式的併發唯一,保險起見,在同一主機上部署多應用例項時,請確保各 WorkerId 唯一。
4️⃣ 異常處理。演算法會丟擲所有 Exception,外部系統應 catch 異常並做好應對處理,以免引發更大的系統崩潰。
5️⃣ 認真理解 IdGeneratorOptions 的定義,這對整合和使用本演算法有幫助。
6️⃣ 使用雪花漂移演算法。雖然程式碼裡包含了傳統雪花演算法的定義,並且你可以在入口處指定(Method=2)來啟用傳統演算法,但仍建議你使用雪花漂移演算法(Method=1,預設的),畢竟它具有更好的伸縮力和更高的效能。
7️⃣ 不要修改核心演算法。本演算法內部引數較多,邏輯較為複雜,在你尚未掌握核心邏輯時,請勿嘗試修改核心程式碼且用於生產環境,除非通過大量細緻、科學的測試驗證。
? 自動註冊WorkerId
? 唯一ID生成器,依賴WorkerId,當業務服務需要水平自動化複製時,就要求它能自動化註冊全域性唯一WorkerId,然後各個容器化的無差別部署的業務服務,才能根據它生產唯一ID。
? 本演算法提供一個開源的動態庫(go語言實現),能在容器 k8s(或其它容器化叢集) 環境下,通過 redis 自動註冊 WorkerId。動態庫提供的C介面方法有:
// 註冊一個新的WorkerId
extern __declspec(dllexport) GoInt RegisterWorkerId(char* ip, GoInt port, char* password, GoInt maxWorkerId);
// 登出WorkerId
extern __declspec(dllexport) void UnRegisterWorkerId();
// 檢查本地WorkerId是否有效
extern __declspec(dllexport) GoUint8 ValidateLocalWorkerId(GoInt workerId);
redis作用
? 只用於註冊 WorkerId ,不用於生產 ID。
? 如果手工指定 WorkerId,即可不依賴 redis。
其它分散式整合
?1.可增加 WorkerIdBitLength 到最大20,支援 1,048,576 個節點,且不影響上述併發效能。[演算法支援]
?2.採用中心化 IdGenerator 叢集,生成可用 Id 列表,存入 Redis 佇列供節點消費。此時64箇中心化節點數足夠大型網際網路專案使用。[需整合方擴充套件實現]
?3.以上2條二選一即可,採用方法2一般是因為不想增加最終 ID 長度,但節點數超過64個。
?4.任何加大 WorkerIdBitLength 或 SeqBitLength 的設定,都可能會增加 ID 的長度。
? 配置變更
配置變更指是系統執行一段時間後,再變更執行引數(IdGeneratorOptions選項值),請注意:
? 1.最重要的一條原則是:BaseTime 只能往前(比老值更小、距離現在更遠)賦值,原因是往後賦值極大可能產生相同的時間戳。[不推薦在系統執行之後調整 BaseTime]
? 2.任何時候增加 WorkerIdBitLength 或 SeqBitLength,都是可以的,但是慎用 “減小”的操作,因為這可能導致在未來某天生成的 ID 與過去老配置時相同。[允許在系統執行之後增加任何一個 BitLength 值]
? 3.如果必須減小 WorkerIdBitLength 或 SeqBitLength 其中的一項,一定要滿足一個條件:新的兩個 BitLength 之和要大於 老的值之和。[不推薦在執行之後縮小任何一個 BitLength 值]
? 4.上述3條規則,並未在本演算法內做邏輯控制,整合方應根據上述規則做好影響評估,確認無誤後,再實施配置變更。
?? 程式碼示例
??️? C#:檢視示例
??️? Java:檢視示例
??️? Go:檢視示例
??️? Rust:檢視示例
??️? C:檢視示例