分布式id解決什么問題 分布式唯一ID



文章插圖
分布式id解決什么問題 分布式唯一ID

文章插圖

【分布式id解決什么問題 分布式唯一ID】在分布式系統中,經常需要對大量的數據、消息、http請求等進行唯一標識,例如鏈路追蹤traceId、身份標識號、訂單流水號、操作記錄流水號、優惠券id等等 。
這個時候數據庫自增主鍵已經不能滿足需求,需要一個能夠生成分布式ID的系統 。
分布式ID的特性全局唯一 。不能出現重復的ID,這是最基本的要求 。遞增 。遞增有利于關系數據庫索引性能 。除了常見的連續遞增,如1001,1002,1003等等,分布式ID還存在趨勢遞增的形式,即保證下一個ID大于上一個ID但不連續 。這樣的好處可以防止關鍵信息被泄露,例如toc業務中暴露給用戶的ID,可能會暴露用戶數量 。(訂單id同理)高可用 。為多個服務提供ID服務,一旦宕機,會造成嚴重影響 。好接入 。秉著拿來即用的設計原則,接入文檔要盡可能的簡單 。高性能:必須要在壓測下表現良好,如果達不到要求則在高并發環境下會導致系統癱瘓 。靈活多變:每個業務場景對ID的要求也各不相同,ID生成要做到靈活多變可配置,盡可能多的滿足需求 。解決方案1. UUID
UUID是Universally Unique Identifier的縮寫,包含32個16進制數字,以連字號分為五段,形式為8-4-4-4-12包含36個字符的字符串,例如:321dsa13-das2-d231-gfdd-213as8asd899
UUID經由一定的算法機器生成,為了保證UUID的唯一性,規范定義了包括網卡MAC地址、時間戳、名字空間、隨機或偽隨機數、時序等元素,以及從這些元素生成UUID的算法 。
優點:
性能非常高,本地生成,沒有網絡消耗 。生成簡單,沒有高可用風險 。有利于信息安全,因為可讀性差,無規律 。
缺點:
太長,不易于存儲 。無序,對MySQL索引不利,在InnoDB中,UUID的無序性可能會引起數據位置頻繁變動,嚴重影響性能 。UUID不能標識業務含義,可讀性差 。2. 數據庫自增 ID
利用數據庫自增ID的特性來生成,如MySQL的auto_increment 。其優點是數字類型,并且可以自增 。當然缺點就是并發場景下的性能瓶頸 。
優點:
簡單,利用數據庫自有功能實現 。ID嚴格連續自增,可以實現一些對ID有特殊要求的業務 。
缺點:
有重復發號的風險,例如MySQL數據庫主從切換的場景 。發號性能限制于數據庫性能 。強依賴數據庫,當數據庫異常時整個系統不可用 。
進一步優化:放棄主從復制的高可用架構,采用多主架構 。每個主庫設置不同的起始值和相同的步長,保證了號段的隔離 。
3. Redis
Redis中的incr命令,可以實現原子自增 。相比較數據庫而言,Redis可支撐的并發量非常高,性能好 。
但需要考慮下面兩種情況造成的數據不一致問題:
宕機后重啟恢復但存在未及時初始化 。主從切換,主從數據同步延遲 。
優點:
簡單,自有能力 。高并發環境下性能好,優于數據庫 。
缺點:
可能會重復發號 。需要保障Redis服務的高可用 。4. Zookeeper 實現
使用ZooKeeper作為分段節點協調工具,每臺服務器首先從Zookeeper 獲取一段號碼,如[1,1000]的ID,此時Zookeeper上保存最大值 1000,每次獲取的時候都會進行判斷,如果ID <=1000,則更新本地的當前值,如果為1001,則會將Zookeeper 上的最大值更新至2000,本地緩存段更新為1001-2000,更新的時候使用分布式鎖來實現 。(相當于用Zookeeper實現了基于數據庫的號段模式)
優點:
效率高 。
缺點:
維護成本較高,不能同時滿足多個系統對ID的需求,不夠靈活 。
5、基于數據庫的號段模式
號段模式的思想是客戶端每次從數據庫中取出一批ID供程序使用,從表中獲取本次ID值的范圍,如[1,1000],然后客戶端將申請的號段[1,1000]加載到內存 。表結構參考如下:
CREATE TABLE id_generator (id int(10) NOT NULL,max_id bigint(20) NOT NULL COMMENT '當前最大id',step int(20) NOT NULL COMMENT '號段的布長',biz_typeint(20) NOT NULL COMMENT '業務類型',version int(20) NOT NULL COMMENT '樂觀鎖版本號',PRIMARY KEY (`id`))等這批號段ID用完,再次向數據庫申請新號段,對max_id字段做一次update操作(update id_generator set max_id = #{max_id+step}, version = version + 1 where version = # {version} and biz_type = XXX),update成功則說明新號段獲取成功,新的號段范圍是(max_id ,max_id +step]
進一步優化:
在號段消耗一半的時候,提前預留下一段號段 。將預留號段時機提前,減少阻塞發生概率 。一般稱此為雙Buffer機制 。不同業務可以設置不同的生成規則 。
5.雪花算法
雪花算法(Snowflake)是twitter公司內部分布式項目采用的ID生成算法,開源后廣受國內大廠的好評,在該算法影響下各大公司相繼開發出各具特色的分布式生成器 。
雪花算法,不依賴其它系統或數據庫,以服務的方式部署,供其它服務調用,穩定性高,生成 ID 的性能也非常高 。
給每臺機器分配一個唯一標識,然后通過下面的結構實現全局唯一ID:
1位 。未使用(二進制中最高位為1的都是負數,所以這個最高位固定是0)41位 。毫秒級時間(41 位的長度可以使用 69 年)10位 。包含5位datacenterId和5位workerId(10位的長度最多支持部署1024個節點)12位 。最后12位是毫秒內的計數(12位的計數順序號支持每個節點每毫秒產生4096個ID序號)
由于在Java中64bit的整數是long類型,所以在Java中SnowFlake算法生成的id就是long來存儲的 。
優點:
生成性能高 。整體上按照時間自增排序 。
缺點:
強依賴機器時鐘,如果時鐘回撥,可能會導致服務異常 。不能同時滿足多個系統對ID的需求,不夠靈活 。在單機上是遞增的,但是由于涉及到分布式環境,每臺機器上的時鐘不可能完全同步,會出現不是全局遞增的情況 。6.Tinyid
Tinyid是滴滴開源的分布式ID生成方案,開源地址見于參考文檔1,只提供基于號段模式來生成ID(加入了雙Buffer機制) 。
7.Uidgenerator
UidGenerator是由百度技術部開發,開源地址見于參考文檔2,基于Snowflake實現的優化算法 。借用未來時間和雙Buffer來解決時間回撥與生成性能等問題,同時結合MySQL進行ID分配 。
8.Leaf
Leaf是美團開源的分布式ID生成方案,開源地址見于參考文檔3 。提供兩種生成的ID的方式:雪花算法模式和號段模式 。可通過配置文件來指定 。
Leaf的雪花算法模式依賴于ZooKeeper,其workId的生成策略是基于ZooKeeper的順序ID來生成的;號段模式也是基于數據庫的號段模式+雙Buffer機制實現的 。