分布式 ID 生成器
分布式 ID 生成器是一種在分布式系統中生成全局唯一、有序的 ID 的算法或工具。在分布式系統中,由于各個節點之間需要共享數據或通信,因此需要一種機制來確保每個節點生成的 ID 是全局唯一的,以避免出現重復或沖突。分布式 ID 生成器就是在這種背景下應運而生的。
分布式 ID 生成器有很多種實現方案,常見的包括:
1. 數據庫自增長序列或字段:利用數據庫的自動遞增功能生成 ID,適用于簡單的分布式系統。
2. UUID(通用唯一識別碼):UUID 是一個由微軟公司開發的 ID 生成算法,生成的 ID 具有較高的唯一性。
3. Snowflake 算法:Snowflake 是 Twitter 開源的分布式 ID 生成算法,生成的 ID 是一個 long 型的值。其核心思想是使用 41bit 作為毫秒數,10bit 作為機器 ID(5 個 bit 是數據中心,5 個 bit 是機器 ID),剩余的 12bit 用于序列號。
4. Redis 生成器:基于 Redis 的分布式 ID 生成器,可以通過 Redis 的計數器功能生成 ID。
5. 基于開源庫的生成器:如 Go 語言中的 idgenerator 庫,Java 中的 Spring Boot ID 生成器等。
分布式 ID 生成器的設計和實現需要考慮性能、可擴展性、可靠性等因素,以滿足分布式系統的需求。
CosId
CosId 旨在提供通用、靈活、高性能的分布式 ID 生成器。
CosIdGenerator : 單機 TPS 性能:1557W/s,三倍于 UUID.randomUUID(),基于時鐘的全局趨勢遞增ID。
SnowflakeId : 單機 TPS 性能:409W/s JMH 基準測試 , 主要解決 時鐘回撥問題 、機器號分配問題、取模分片不均勻問題 并且提供更加友好、靈活的使用體驗。
SegmentId: 每次獲取一段 (Step) ID,來降低號段分發器的網絡IO請求頻次提升性能。
RedisIdSegmentDistributor: 基于 Redis 的號段分發器。
JdbcIdSegmentDistributor: 基于 Jdbc 的號段分發器,支持各種關系型數據庫。
ZookeeperIdSegmentDistributor: 基于 Zookeeper 的號段分發器。
MongoIdSegmentDistributor: 基于 MongoDB 的號段分發器。
IdSegmentDistributor: 號段分發器(號段存儲器)
SegmentChainId(推薦):SegmentChainId (lock-free) 是對 SegmentId 的增強。性能可達到近似 AtomicLong 的 TPS 性能:12743W+/s JMH 基準測試 。
背景(為什么需要分布式ID)
在軟件系統演進過程中,隨著業務規模的增長 (TPS/存儲容量),我們需要通過集群化部署來分攤計算、存儲壓力。應用服務的無狀態設計使其具備了伸縮性。在使用 Kubernetes 部署時我們只需要一行命令即可完成服務伸縮 (kubectl scale --replicas=5 deployment/order-service
)。
但對于有狀態的數據庫就不那么容易了,此時數據庫變成系統的性能瓶頸是顯而易見的。
分庫分表
從微服務的角度來理解垂直拆分其實就是微服務拆分。以限界上下文來定義服務邊界將大服務/單體應用拆分成多個自治的粒度更小的服務,因為自治性規范要求,數據庫也需要進行業務拆分。但垂直拆分后的單個微服務依然會面臨 TPS/存儲容量 的挑戰,所以這里我們重點討論水平拆分的方式。
數據庫分庫分表方案是邏輯統一,物理分區自治的方案。其核心設計在于中間層映射方案的設計 (上圖 Mapping),即分片算法的設計。幾乎所有編程語言都內置實現了散列表(java:HashMap
/csharp:Dictionary
/python:dict
/go:map
...)。分片算法跟散列表高度相似(hashCode
),都得通過 key
/shardingValue
映射到對應的槽位(slot
)。
那么 shardingValue
從哪里來呢?CosId!!!
當然還有很多分布式場景需要分布式ID,這里不再一一列舉。
分布式ID方案的核心指標
全局(相同業務)唯一性:唯一性保證是ID的必要條件,假設ID不唯一就會產生主鍵沖突,這點很容易可以理解。
有序性:有序性保證是面向查詢的數據結構算法(除了Hash算法)所必須的,是二分查找法(分而治之)的前提。
吞吐量/性能(ops/time):即單位時間(每秒)能產生的ID數量。生成ID是非常高頻的操作,也是最為基本的。假設ID生成的性能緩慢,那么不管怎么進行系統優化也無法獲得更好的性能。
穩定性(time/op):穩定性指標一般可以采用每個操作的時間進行百分位采樣來分析,比如 CosId 百分位采樣 P9999=0.208 us/op,即 0% ~ 99.99% 的單位操作時間小于等于 0.208 us/op。
百分位數 WIKI :統計學術語,若將一組數據從小到大排序,并計算相應的累計百分點,則某百分點所對應數據的值,就稱為這百分點的百分位數,以Pk表示第k百分位數。百分位數是用來比較個體在群體中的相對地位量數。
為什么不用平均每個操作的時間:馬老師的身價跟你的身價能平均么?平均后的值有意義不?
可以使用最小每個操作的時間、最大每個操作的時間作為參考嗎?因為最小、最大值只說明了零界點的情況,雖說可以作為穩定性的參考,但依然不夠全面。而且百分位數已經覆蓋了這倆個指標。
自治性(依賴):主要是指對外部環境有無依賴,比如號段模式會強依賴第三方存儲中間件來獲取NexMaxId
。自治性還會對可用性造成影響。
可用性:分布式ID的可用性主要會受到自治性影響,比如SnowflakeId會受到時鐘回撥影響,導致處于短暫時間的不可用狀態。而號段模式會受到第三方發號器(NexMaxId
)的可用性影響。
可用性 WIKI :在一個給定的時間間隔內,對于一個功能個體來講,總的可用時間所占的比例。
MTBF:平均故障間隔
MDT:平均修復/恢復時間
Availability=MTBF/(MTBF+MDT)
假設MTBF為1年,MDT為1小時,即Availability=(365*24)/(365*24+1)=0.999885857778792≈99.99%
,也就是我們通常所說對可用性4個9。
適應性:是指在面對外部環境變化的自適應能力,這里我們主要說的是面對流量突發時動態伸縮分布式ID的性能,
存儲空間:還是用MySq-InnoDB B+樹來舉例,普通索引(二級索引)會存儲主鍵值,主鍵越大占用的內存緩存、磁盤空間也會越大。Page頁存儲的數據越少,磁盤IO訪問的次數會增加。總之在滿足業務需求的情況下,盡可能小的存儲空間占用在絕大多數場景下都是好的設計原則。
不同分布式ID方案核心指標對比
分布式ID | 全局唯一性 | 有序性 | 吞吐量 | 穩定性(1s=1000,000us) | 自治性 | 可用性 | 適應性 | 存儲空間 |
---|
UUID/GUID | 是 | 完全無序 | 3078638(ops/s) | P9999=0.325(us/op) | 完全自治 | 100% | 否 | 128-bit |
SnowflakeId | 是 | 本地單調遞增,全局趨勢遞增(受全局時鐘影響) | 4096000(ops/s) | P9999=0.244(us/op) | 依賴時鐘 | 時鐘回撥會導致短暫不可用 | 否 | 64-bit |
SegmentId | 是 | 本地單調遞增,全局趨勢遞增(受Step影響) | 29506073(ops/s) | P9999=46.624(us/op) | 依賴第三方號段分發器 | 受號段分發器可用性影響 | 否 | 64-bit |
SegmentChainId | 是 | 本地單調遞增,全局趨勢遞增(受Step、安全距離影響) | 127439148(ops/s) | P9999=0.208(us/op) | 依賴第三方號段分發器 | 受號段分發器可用性影響,但因安全距離存在,預留ID段,所以高于SegmentId | 是 | 64-bit |
有序性(要想分而治之·二分查找法,必須要維護我)
剛剛我們已經討論了ID有序性的重要性,所以我們設計ID算法時應該盡可能地讓ID是單調遞增的,比如像表的自增主鍵那樣。但是很遺憾,因全局時鐘、性能等分布式系統問題,我們通常只能選擇局部單調遞增、全局趨勢遞增的組合(就像我們在分布式系統中不得不的選擇最終一致性那樣)以獲得多方面的權衡。下面我們來看一下什么是單調遞增與趨勢遞增。
CosId VS 美團 Leaf
CosId (SegmentChainId
) 性能是 Leaf(segment
) 的 5 倍。
開源的分布式ID
開源的分布式 ID 生成器有很多種,以下是一些較為知名的:
1. Twitter 的 Snowflake 算法:Snowflake 是 Twitter 開源的分布式 ID 生成算法,生成的 ID 是一個 long 型的值。其核心思想是使用 41bit 作為毫秒數,10bit 作為機器 ID(5 個 bit 是數據中心,5 個 bit 是機器 ID),剩余的 12bit 用于序列號。
2. 美團的 Leaf 項目:Leaf 是美團開源的分布式 ID 生成項目,基于 Snowflake 算法,支持 RPC 方式調用,據官方提供的信息,其 QPS 壓測結果近 5w/s,tp999,1ms。
3. 百度的 UidGenerator:UidGenerator 是百度開源的一款分布式高性能的唯一 ID 生成器,基于 Twitter 的 Snowflake 算法實現,支持自定義時間戳、工作機器 id 和序列號。
4. 滴滴的 Tinyid:Tinyid 是滴滴開源的分布式 ID 生成器,基于 Snowflake 算法,適用于小規模的分布式系統。
這些開源的分布式 ID 生成器在不同的場景和需求下有著各自的優勢和特點,可以根據實際需求選擇適合的生成器來實現。
該文章在 2023/10/30 11:19:42 編輯過