Yige

Yige

Build

分布式ID生成

分布式 ID 生成方案#

內容來自

  1. 那些驚艷的算法們(四)—— 唯一 ID 生成器 snowflake
  2. 分布式 ID 生成器解決方案
  3. 高併發情況下分布式全局 ID

問題描述#

在單機系統中 (例如一個 MySQL 實例), unique ID 的生成是非常簡單的,直接利用 MySQL 自帶的自增 ID 功能就可以實現.

但在一個存在多個 Shards 的分布式系統 (例如多個 MySQL 實例組成一個集群,在這個集群中插入數據), 這個問題會變得複雜,所生成的全局的 unique ID 要滿足以下需求:

  • 保證生成的 ID 全球唯一
  • 今後數據在多個 Shards 之間遷移不會受到 ID 生成方式的限制
  • 生成的 ID 中最好能帶上時間信息,例如 ID 的前 k 位是 Timestamp, 這樣能夠直接通過對 ID 的前 k 位的排序來對數據按時間排序
  • 生成的 ID 最好不大於 64 bits
  • 生成 ID 的速度有要求。例如,在一個高吞吐量的場景中,需要每秒生成幾萬個 ID (Twitter 最新的峰值達到了 143,199 Tweets/s, 也就是 10 萬 +/ 秒)
  • 整個服務最好沒有單點

時間戳#

用時間做唯一 id,這個在併發比較高或者分布式環境中基本不可行,統一時間生成的 id 是重複的,不滿足全球唯一

利用數據庫自增#

依然利用數據庫產生自增 id,保證唯一性。但是要注意的是沒有分庫分表,可以單獨使用固定數量的數據庫表專門來產生自增 ID,與業務無關,後續不再分表。
好處是實現簡單,容易理解。不足在於 id 產生速率受數據庫性能以及連接數據庫的網絡影響

利用 Redis 原子操作#

  • 不依賴於數據庫,靈活方便,且性能優於數據庫。
  • 數字 ID 天然排序,對分頁或者需要排序的結果很有幫助

注意:

  • 在 Redis 集群情況下,需要設置不同的增長步長
  • 生成的 ID 超過自增增長的話,可以採用前綴 + 自增 + 並且設置有效期

利用 UUID/GUID#

基本概念#

UUID 是指在一台機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。
UUID 組成部分:當前日期和時間 + 時鐘序列 + 隨機數 + 全球唯一的 IEEE 機器識別號

優缺點#

優點:

  • 簡單,代碼方便
  • 生成 ID 性能非常好,基本不會有性能問題
  • 全球唯一,在遇見數據遷移,系統數據合併,或者數據庫變更等情況下,可以從容應對
    缺點:
  • 沒有排序,無法保證趨勢遞增
  • UUID 往往是使用字符串存儲,查詢的效率比較低
  • 存儲空間比較大,如果是海量數據庫,就需要考慮存儲量的問題。
  • 太長,128bit,不適合做數據庫主鍵

Twitter Snowflake#

snowflake 是 Twitter 開源的分布式 ID 生成算法,結果是一個 long 型的 ID。
其核心思想是:高位隨機 + 毫秒數 + 機器碼(數據中心 + 機器 id)+10 位的流水號

ID 生成過程#

image.png

  • 10 bits 的機器號,在 ID 分配 Worker 啟動的時候,從一個 Zookeeper 集群獲取 (保證所有的 Worker 不會有重複的機器號)
  • 41 bits 的 Timestamp: 每次要生成一個新 ID 的時候,都會獲取一下當前的 Timestamp, 然後分兩種情況生成 sequence number:
    1. 如果當前的 Timestamp 和前一個已生成 ID 的 Timestamp 相同 (在同一毫秒中), 就用前一個 ID 的 sequence number + 1 作為新的 sequence number (12 bits); 如果本毫秒內的所有 ID 用完,等到下一毫秒繼續 (這個等待過程中,不能分配出新的 ID)
    2. 如果當前的 Timestamp 比前一個 ID 的 Timestamp 大,隨機生成一個初始 sequence number (12 bits) 作為本毫秒內的第一個 sequence number 整個過程中,只是在 Worker 啟動的時候會對外部有依賴 (需要從 Zookeeper 獲取 Worker 號), 之後就可以獨立工作了,做到了去中心化
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。