分佈式 ID 生成策略 —— 聽雲資深 Java 工程師

本文截取自oschina的一篇討論文章中“宇智波唐嫣”的發言,如果想查看整個討論原文的,可訪問原文,地址如下:http://www.oschina.net/question/865233_2137987?sort=default&p=1#answers

以下是“宇智波唐嫣”的發言

@Burn1ng1ce :先推薦你看 Instagram 的這篇 [0],他們要求生成 ID 儘量短而且可按生成時間排序,裏面提到了好幾種不同的 ID 生成方法的優缺點,比如:

  • 在應用裏面直接生成 UUID,優點是獨立生成、性能好,缺點是生成的 ID 比較長。
  • 單獨運行一套 ID 生成服務,比如 Twitter 的 Snowflake [1],優點是可以生成比較短而且可以排序的 ID,並且分佈式系統不容易掛,缺點是維護麻煩。
  • 依賴數據庫自增,比如 Flickr [2],優點是可以重用現有的計數,缺點是數據庫寫性能可能會是瓶頸,並且如果使用多個數據庫,如何保證生成的 ID 可排序是個問題。
Instagram 然後根據自己的需要定製了基於 PostgreSQL 數據庫的預分片 (pre-sharding) ID 生成機制。核心思想是預先分配足量的邏輯片 (logical shard),然後將大量的邏輯片映射到少量的物理片 (physical shard),最終依賴數據庫的自增特性保證 ID 的唯一性。


注意以上提到的幾套機制生成的都是 64 位的整數 ID,主要是給程序用來標記新建的數據對象用的。而原題目提到的用戶 ID,我理解除了給程序用外,更重要的是要給人看。給人看的 ID 需要更加簡短,因爲對機器來說,64 位已經足夠短了,而顯然人是無法快速記憶 8744239352046571174 這樣一長串數字的。所以生成給人看的 ID 需要根據應用場景儘可能短,比如絕大部分時候用戶數量不會過億,那麼生成的 ID 的十進制表達最好不要超過 8 位數。

題目中要求的另外一點『不能直接看出規則』也是需要特別考慮的。對於中國互聯網這樣沒有任何道德底限的地方來說尤爲重要。原因大家都懂,如果 ID 是連續的,扒取內容的工作就非常簡單了,直接按順序下載指定的 URL 範圍即可,爬蟲都不用寫了。所以對於公開 ID,不連續、無規則是基本要求。

以上兩點和前述 Instagram 文章提到的幾種 ID 生成需求有本質不同。結合知乎的用例,我把題目提到的這種 ID 需求特性概括爲九個字:儘量短、無規則、無順序。對於這樣的應用場景,個人認爲寫一套單獨的 ID 生成服務是比較好的辦法。這個功能很簡單,依賴過多的外部組件(如數據庫)有點得不償失。

目前我正在寫的 ID 生成服務的基本思路是這樣的:
  • ID 生成服務管理多個不同名字的 ID 池 (pool)。
  • 每種不同類型的 ID 屬於不同的 ID 池,比如知乎會有用戶 ID 池、問題 ID 池、回答 ID 池等等。
  • 每個 ID 池由多個定長 ID 塊 (block) 構成。
  • 每個 ID 塊包含一段連續的 ID,比如第一塊是從 0~1023,第二塊從 1024~2047,以此類推。
  • 每個 ID 塊並不完全分配,而是按照一個給定的填充率 (fill ratio) 隨機選擇來分配,比如假設填充率是 50%,那麼每個 ID 塊中只有大約一半的 ID 會被分配。也就是說每個 ID 塊是有隨機空洞的。
  • 如果某個 ID 塊中可用 ID 被分配完畢,服務會自動生成下一個新的 ID 塊,並按照填充率去掉不可用 ID。生成新的 ID 塊時需要記錄下最後一個 ID 塊的起始 ID。
  • 已經分配過的 ID 會寫入一個 append-only 日誌。新的 ID 塊生成時會創建一個新的 append-only 日誌(因爲舊的已經不需要了)。
  • 服務重新啓動的時候先拿到最後一個 ID 塊的起始 ID,再讀取 append-only 日誌將已經分配過的 ID 剔除,再剔除掉部分未分配的 ID 以維持填充率。
  • 客戶端發送請求訪問 ID 生成服務。服務端返回 ID 做爲回覆。

優點是邏輯簡單,生成的 ID 短小,單個進程維護起來方便。缺點是知道生成的 ID 的上限(可以用很大的塊部分解決這個問題)。大概這樣。歡迎討論。

[0]: http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram
[1]: https://github.com/twitter/snowflake
[2]: http://code.flickr.com/blog/20


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