業務系統需要什麼樣的ID生成器

2021-07-10 23:54:35 字數 2886 閱讀 1079

18 january 2015

id 生成器在微博我們一直叫發號器,微博就是用這樣的號來儲存,而我微博裡討論的時候也都是以發號器為標籤。它的主要目的確如平常大家理解的「為乙個分布式系統的資料object產生乙個唯一的標識」,但其實在乙個真實的系統裡可能也可以承擔更多的作用。概括起來主要有以下幾點:

唯一性時間相關

粗略有序

可反解可製造

下面我會分別講每個作用後面的考慮和權衡,也會對比介紹一下業界已知的幾種 id 設計。

要唯一性,是否需要全域性唯一?

說起全域性唯一,通常大家都會在想到發號器服務,分布式的通常需要更大空間,中心式的則需要在乙個合適的地方在會聚。這就可能涉及到鎖,而鎖意味著成本和效能的下降。所以當前的系統是否需要全域性的唯一性,就是乙個需要考慮的問題。

比如在通訊系統裡,聊天訊息可能就未必需要全域性,因為一條訊息只是某乙個人發出,系統只要保證乙個人維度的唯一性即可。本質上而言,這裡利用了使用者 id 的唯一性,因為唯一性是可以依賴的,通常我們設計系統也都是基於類似的性質,比如後面降到的使用時間唯一性的方式。

用時間來做什麼?千萬年太久,只爭朝夕?

前面說到唯一性可以依賴,我們需要選擇的是依賴什麼。通常的做法可以選擇資料庫自增,這在很多資料庫裡都是可以滿足acid 的操作。但是用資料庫有個缺點,就是資料庫有效能問題,在多機房情況下也很難處理。當然,你可以通過調整自增的步長來設計,但對於乙個發號器而言,操作和維護都略重了。

而時間是天然唯一的,因此也是很多設計的選擇。但對於乙個8byte的 id 而言,時間並沒有那麼多。你如果精確到秒級別,三十年都要使用30bit,到毫秒級則要再增加10bit,你也只剩下20bit 可以做其他事情了。之所以在8byte 上搗鼓,因為8byte 是乙個long,不管在處理器和編譯器還是語言層面,都是可以更好地被處理。

然而三十年夠麼?對於乙個人來說,可能不夠,但對乙個系統而言,可能足夠。我們經常開玩笑,網際網路裡能活三十年的系統有多少呢?三十年過去,你的系統可能都被重寫 n 遍了。這樣的信心同樣來自於摩爾定律,三十年後,計算效能早就提高了上千倍,到時候更多byte 都不會是問題了。

粗略有多粗略,秒還是毫秒?

每秒乙個或者每毫秒乙個id明顯是不夠的,剛才說到還有20bit 可以做其他事情,就包括乙個sequenceid。如果要達到精確的有序,就要對 sequence 進行併發控制,效能上肯定會打折。所以經常會有的乙個選擇就是,在這個秒的級別上不再保證順序,而整個 id 則只保證時間上的有序。後一秒的 id肯定比前一秒的大,但同一秒內可能後取的id比前面的號小。這在使用時非常關鍵,你要理解,系統也要接受才可以。

那時間用秒還是毫秒呢?其實不用毫秒的時候就可以把空出來的10bit 送給 sequence,但整個id 的精度就下降了。峰值速度是更現實的考慮。sequence 的空間決定了峰值的速度,而峰值也就意味著持續的時間不會太久。這方面,每秒100萬比每毫秒1000限制更小。

可反解,解開的是什麼?

乙個 id 生成之後,就會伴隨著資訊終身,排錯分析的時候,我們需要查驗。這時候乙個可反解的 id 可以幫上很多忙,從**來的,什麼時候出生的。 跟身份證倒有點兒相通了,其實身份證就是乙個典型的分布式 id 生成器。

如果id 裡已經有了時間而且能解開,在儲存層面可能不再需要timestamp 一類的字段了。微博的 id 還有很多業務資訊,這個後面會細講。

可製造,為什麼不用uuid?

網際網路系統上可用性永遠是優先指標。但由於分布式系統的脆弱,網路不穩定或者底層儲存系統的不可用,業務系統隨時面臨著失敗。為了給前端更友好的響應,我們需要能盡量容忍失敗。比如在儲存失敗時,可能需要臨時匯出請求供後續處理,而後續處理時已經離開了當時的時間點,順序跟其他系統錯開了。我們需要製造出這樣的id 以便系統好像一直正常執行一樣,可製造的 id 讓你可以控制生產日期(汗,有點兒假冒偽劣的意思了),然後繼續下面的處理。

另乙個重要場景就是資料清洗。這個屬於較少遇到,但並不罕見的情況,可能是原來 id 設計的不合理,也可能由於底層儲存的改變,都可能出現。這樣乙個可製造的 id 就會帶來很多操作層面的便利。

這也是我們不用 uuid 的乙個原因。uuid 標準可以保證在某時某地生成,但如果要控制生成乙個特定時間的 uuid,可能需要底層庫的改動。經驗告訴我們,能在上層解決的問題不要透到下層,這種庫的維護成本是非常高的。

uuid 就不說了, 其他公開出來的這裡說下snowflake、weibo以及 ticktick 的設計。

snowflake

41bit留給毫秒時間,10bit給machineid,也就是機器要預先配置,剩下12位留給sequence。**雖然露出來了,但其實已經不可用了,據說是內部改造中。

weibo

微博使用了秒級的時間,用了30bit,sequence 用了15位,理論上可以搞定3.2w/s的速度。用4bit來區分idc,也就是可以支援16個 idc,對於核心機房來說夠了。剩下的有2bit 用來區分業務,由於當前發號服務是機房中心式的,1bit 來區分熱備。是的,也沒有用滿64bit。

ticktick

也就是當前在環信系統裡要用到的。使用了30bit 的秒級時間,20bit 給sequence。這裡是有個考慮,第一版實現還是希望到毫秒級,所以20bit 的前10bit給了毫秒來用,剩下10bit給 sequence。等到峰值提高的時候可以暫時回到秒級。

前面說到的三十年問題,因此我在高位留了2bit 做 version,或者到時候改造使用更長位元組數,用第一位來標識不同 id,或者可以把這2bit 挪給時間用,可以給系統改造留出一定的時間。

剩下的10bit 留給 machineid,也就是說當前 id 生成可以直接內嵌在業務服務中,最多支援千級別的伺服器數量。最後有2bit 做tag 用,可能區分群訊息和單聊訊息。同時你也看出,這個 id 最多支援一天10億訊息,也是怕系統增速太快,這2bit 可以挪給 sequence,可以支援40億級別訊息量,或者結合前面的版本支援到百億級別。

自己實現乙個發號器非常簡單,所以ticktick 怎麼實現並不重要。不過吶,我還是有 demo 原始碼的,見

我們需要什麼樣的測試?

左耳朵耗子發表了 我們需要全職的qa嗎?後,一石激起千重浪,贊成者有之,激烈反對者有之 有人說文中對qa的定義不對,還有人說以偏概全 的確,在需不需要專職的qa角色這個問題上,很難用乙個簡單的 需要 或 不需要 來回答。前兩天我寫了一篇對該文的回應文章,但由於文章寫就得比較倉促,很多觀點來不及完整表...

我們需要什麼樣的計算

本文選自 讓雲觸手可及 微軟雲計算實踐指南 一書 我們需要什麼樣的計算 我認為全球電腦市場的規模大約為5臺。ibm創始人托馬斯 j 沃森 thomas j.watson 1943 當我們站在微軟美國芝加哥資料中心一層的時候,資料中心管理人員告訴我這一層有好幾萬臺計算機,但是我們一台也沒看到。這是我見...

未來需要什麼樣的軟體人才

捷克首都布拉格,一座美麗而古老的山城,伏爾塔瓦河像一條綠色的玉帶穿城而過,橫跨在河上的十幾座古老和現代的大橋雄偉壯觀,市區那帶有尖塔或圓頂的古老建築,無論是羅馬式 哥德式 巴羅克式還是文藝復興式,都完好地儲存著,高高低低的塔尖毗連成片,在陽光照耀下顯得金碧輝煌。就在這布拉格之春,3月28日到4月1日...