原文鏈接:何曉東 博客
文章起源於 康神交流羣的 panda大佬和boss li關於發號器的一些交流,特此感謝讓我們學到了新知識。
爲什麼需要發號器
在分佈式系統中,經常需要對大量的數據、消息、http 請求等進行唯一標識,例如:對於分佈式系統,服務間相互調用需要唯一標識,調用鏈路分析,日誌追蹤的時候需要使用這個唯一標識。此時需要一個全局唯一的 ID。
需要什麼樣子的發號器
持久化
要滿足長期全局唯一,持久化是必須的,肯定不能讓已經使用的再次產生一遍,同時需要強一致性。可用選擇存儲在 Redis 或者 Etcd 中。
高可用
這個時候需要提供發號器服務的機器主從同步,能夠在主服務器宕機的時候,自動選擇從服務器,切換過程中,發號器生成的 ID 可能不連續,服務正常就可以。
其他特性
主要是看具體業務了,需要認證和權限控制都是可選的,可用在請求層限制來源 IP,只允許固定的 IP 訪問。
發號器的幾種常用方案
UUID
UUID 是 Universally Unique Identifier 的縮寫,它是在一定的範圍內(從特定的名字空間到全球)唯一的機器生成的標識符,UUID 是16字節128位長的數字,通常以36字節的字符串表示,比如:3F2504E0-4F89-11D3-9A0C-0305E82C3301。
UUID經由一定的算法機器生成,爲了保證 UUID 的唯一性,規範定義了包括網卡 MAC 地址、時間戳、名字空間(Namespace)、隨機或僞隨機數、時序等元素,以及從這些元素生成 UUID 的算法。UUID 的複雜特性在保證了其唯一性的同時,意味着只能由計算機生成。
優缺點: 本地生成,性能高,延遲低,位數長,不適用當作索引字段,同時是無序的,難以根據特徵分析趨勢。
類snowflake算法
snowflake是twitter開源的分佈式ID生成算法,其核心思想爲,一個long型的ID:
41bit作爲毫秒數 - 10bit作爲機器編號 - 12bit作爲毫秒內序列號
算法單機每秒內理論上最多可以生成1000*(2^12),也就是400W的ID,
優缺點: 整個 ID 都是自增的,這個非常適合查看趨勢,同時生成不依賴於第三方系統,可靠性很高,可調整性也很高。缺點就是嚴重依賴機器時鐘。
基於MySQL的發號器
字段設置 auto_increment_increment
和 auto_increment_offset
來保證 ID 自增,每次業務使用下列 SQL 讀寫 MySQL 得到 ID。
begin;
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
commit;
爲了保證高可用,需要有多臺 MySQL 機器,也需要爲每臺機器設置不同的自增起始值和步長,例如:
# TicketServer1:
auto-increment-increment = 2
auto-increment-offset = 1
# TicketServer2:
auto-increment-increment = 2
auto-increment-offset = 2
優缺點: 簡單可靠,成本很小,由專業 DBA 進行維護就可以的。ID 單調遞增,有合適的業務是最好的。缺點就是強依賴於數據庫,修改起點和步長優點困難,同時也需要額外保證數據庫的穩定可用。每次請求都去額外讀寫數據庫的情況下,造成數據庫壓力很大,需要消耗很多資源。
以上就是最常用的三種全局唯一 ID 生成方案,採用較多的是類 snowflake 的方案,如果請求數列不是很高,可以調低時間的精度等,靈活性很高。生成的 ID 時間趨勢自增,甚至可以用來做索引字段,佔用空間較小。後期對數據進行分析的時候也很方便。
生產環境唯一ID的使用
類 snowflake 的方案,會採用請求時生成的方式,無法提前生成。
基於 MySQL 的發號器,或者 uuid 模式的,可用提前生成一大批數據,根據業務去定生成數量,放到內存,MQ 或者 Redis List中,業務申請唯一 ID 的時候,直接從其中彈一個出來。同時加一個異步定時任務,固定時間計算一下隊列中剩餘的唯一 ID 數量,數量不足時及時的再次生成一大批,加入到備選隊列。
Go snowflake的demo:
參考文章:
一如既往,推薦幾個 高質量課程,你學到新東西,我賺點佣金,大家都是贏家。