高併發系統設計八-發號器-如何保證分庫分表後ID的全局唯一性

1、分庫分表後帶來的問題

  • 查詢的時候必須帶着分區鍵字段
  • 一個聚合類查詢性能比較差,需要考慮使用計數器等其他的解決方案
  • 主鍵的全局唯一性問題

2、數據庫中的主鍵要如何選擇

數據庫中的每一條記錄都需要有一個唯一的標識,依據數據庫的第二範式,數據庫中每一個表中都需要有一個唯一的主鍵,其他數據元素和主鍵一一對應。

  • 使用業務字段作爲主鍵

比如用戶表中使用手機號碼,email或者身份證號碼作爲主鍵。但是有的不是太適用,比如要考慮作爲主鍵的業務字段能否唯一標識一個人,一個人可能會有多個手機號碼,email,身份證號碼可以是用戶的唯一標識,但是它有屬於隱私屬性,還有就是已有的身份證號碼可能會變更,比如在1999年時身份證號碼從15位變更爲了18位。

  • 使用生成的唯一 ID 作爲主鍵

這種方式的話,可以保證唯一性,生成後也不會更改,可以隨意引用。

單庫單表的場景下,使用數據庫的自增字段作爲ID,但是在分庫分表後,使用自增字段就無法保證ID的全局唯一性。

使用UUID作爲主鍵會有什麼問題

  • 生成的ID最好具有單調遞增性(有序,ID可能會成爲排序字段),而UUID不具備這個。
  • ID有序會提升數據的寫入性能。

MySQL InnoDB 存儲引擎使用 B+ 樹存儲索引數據,而主鍵也是一種索引。索引數據在 B+ 樹中是有序排列的。


當插入的下一條記錄的 ID 是遞增的時候,比如插入 30 時,數據庫只需要把它追加到後面就好了。但是如果插入的數據是無序的,比如 ID 是 13,那麼數據庫就要查找 13 應該插入的位置,再挪動 13 後面的數據,這就造成了多餘的數據移動的開銷

  • UUID不具備業務含義。
  • UUID 是由 32 個 16 進制數字組成的字符串,如果作爲數據庫主鍵使用比較耗費空間。

3、基於 Snowflake 算法搭建發號器

運用它去解決 ID 全局唯一性的問題。

Snowflake 的核心思想是將 64bit 的二進制數字分成若干部分,每一部分都存儲有特定含義的數據,比如說時間戳、機器 ID、序列號等等,最終生成全局唯一的有序 ID


不同公司也會依據自身業務的特點對 Snowflake 算法做一些改造,比如說減少序列號的位數增加機器 ID 的位數以支持單 IDC 更多的機器,也可以在其中加入業務 ID 字段來區分不同的業務。比方說我現在使用的發號器的組成規則就是:1 位兼容位恆爲 0 + 41 位時間信息 + 6 位 IDC 信息(支持 64 個 IDC)+ 6 位業務信息(支持 64 個業務)+ 10 位自增信息(每毫秒支持 1024 個號)

3.1、實現方式

  • 嵌入到業務代碼中(分佈在業務服務器中)。
    • 好處是業務代碼在使用的時候不需要跨網絡調用,性能上會好一些,
    • 但是就需要更多的機器 ID 位數來支持更多的業務服務器。
    • 由於業務服務器的數量很多,我們很難保證機器 ID 的唯一性,所以就需要引入 ZooKeeper 等分佈式一致性組件來保證每次機器重啓時都能獲得唯一的機器 ID。
  • 作爲獨立的服務進行部署-發號器服務。
    • 多一次的網絡調用
    • 微博和美圖都是使用獨立服務的方式來部署發號器的,性能上單實例單 CPU 可以達到兩萬每秒

3.2、實際項目中可能遇到的問題

如果請求發號器的 QPS 不高,比如說發號器每毫秒只發一個 ID,就會造成生成 ID 的末位永遠是 1,那麼在分庫分表時如果使用 ID 作爲分區鍵就會造成庫表分配的不均勻

  • 時間戳不記錄毫秒而是記錄秒,這樣在一個時間區間裏可以多發出幾個號,避免出現分庫分表時數據分配不均
  • 生成的序列號的起始號可以做一下隨機,這一秒是 21,下一秒是 30,這樣就會盡量地均衡了

4、其他方案

  • 滴滴和美團都有提出基於數據庫生成 ID 的方案。這些方法根植於公司的業務,同樣能解決分佈式環境下 ID 全局唯一性的問題

  • 百度開源的UidGenerator(僅支持單機部署)使用Snowflake算法,單機QPS可達600萬。項目說明:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md 。

  • 美團Leaf(分佈式ID生成系統),QPS近5萬。項目地址:https://tech.meituan.com/2017/04/21/mt-leaf.html 。

  • 微信序列號生成器
    文檔地址:https://www.infoq.cn/article/wechat-serial-number-generator-architecture

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章