六種分散式ID生成方法「分散式id是什麼意思」

在分散式系統中,經常需要對大量的數據、消息、http請求等進行唯一標識,例如鏈路追蹤traceId、身份標識號、訂單流水號、操作記錄流水號、優惠券id等等。

這個時候資料庫自增主鍵已經不能滿足需求,需要一個能夠生成分散式ID的系統。

分散式ID的特性

  1. 全局唯一。不能出現重複的ID,這是最基本的要求。
  2. 遞增。遞增有利於關係資料庫索引性能。除了常見的連續遞增,如1001,1002,1003等等,分散式ID還存在趨勢遞增的形式,即保證下一個ID大於上一個ID但不連續。這樣的好處可以防止關鍵信息被泄露,例如toc業務中暴露給用戶的ID,可能會暴露用戶數量。(訂單id同理)
  3. 高可用。為多個服務提供ID服務,一旦宕機,會造成嚴重影響。
  4. 好接入。秉著拿來即用的設計原則,接入文檔要儘可能的簡單。
  5. 高性能:必須要在壓測下表現良好,如果達不到要求則在高並發環境下會導致系統癱瘓。
  6. 靈活多變:每個業務場景對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的演算法。

優點:

  1. 性能非常高,本地生成,沒有網路消耗。
  2. 生成簡單,沒有高可用風險。
  3. 有利於信息安全,因為可讀性差,無規律。

缺點:

  1. 太長,不易於存儲。
  2. 無序,對MySQL索引不利,在InnoDB中,UUID的無序性可能會引起數據位置頻繁變動,嚴重影響性能。
  3. UUID不能標識業務含義,可讀性差。

2. 資料庫自增 ID

利用資料庫自增ID的特性來生成,如MySQL的auto_increment。其優點是數字類型,並且可以自增。當然缺點就是並發場景下的性能瓶頸。

優點:

  1. 簡單,利用資料庫自有功能實現。
  2. ID嚴格連續自增,可以實現一些對ID有特殊要求的業務。

缺點:

  1. 有重複發號的風險,例如MySQL資料庫主從切換的場景。
  2. 發號性能限制於資料庫性能。
  3. 強依賴資料庫,當資料庫異常時整個系統不可用。

進一步優化:
放棄主從複製的高可用架構,採用多主架構。每個主庫設置不同的起始值和相同的步長,保證了號段的隔離。

3. Redis

Redis中的incr命令,可以實現原子自增。相比較資料庫而言,Redis可支撐的並發量非常高,性能好。

但需要考慮下面兩種情況造成的數據不一致問題:

  1. 宕機後重啟恢復但存在未及時初始化。
  2. 主從切換,主從數據同步延遲。

優點:

  1. 簡單,自有能力。
  2. 高並發環境下性能好,優於資料庫。

缺點:

  1. 可能會重複發號。
  2. 需要保障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_type    int(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:

一文了解分散式系統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來存儲的。

優點:

  1. 生成性能高。
  2. 整體上按照時間自增排序。

缺點:

  1. 強依賴機器時鐘,如果時鐘回撥,可能會導致服務異常。
  2. 不能同時滿足多個系統對ID的需求,不夠靈活。
  3. 在單機上是遞增的,但是由於涉及到分散式環境,每台機器上的時鐘不可能完全同步,會出現不是全局遞增的情況。

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機制實現的。

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/252988.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-14 02:24
下一篇 2024-12-14 02:24

相關推薦

發表回復

登錄後才能評論