?背景 ?
對于一套分布式部署的 IM 系統(tǒng),要求每條消息的 ID 要保證在集群中全局*且按生成時間有序排列。如何快速高效的生成消息數(shù)據(jù)的* ID ,是影響系統(tǒng)吞吐量的關鍵因素。那么,融云是如何做到生成全局*消息 ID 的呢?
首先需要明確下 ID 生成的核心需求:
1. 全局*
2. 有序
?設計 ?
融云消息數(shù)據(jù)的* ID 長度采用 80 Bit 。每 5 個 Bit ,進行一次 32 進制編碼,轉換為一個字符,字符取值范圍是,( 2 ~ 9 ) 和 ( A ~ B ),其中,已經去掉容易造成肉眼混淆的,數(shù)字 0 和 1 ,及字母 O 和 I 。這樣,80 Bit 可以轉換為 16 個字符,再加上 3 個分隔符( - ),將 16 個字符分為 4 組,*終得到一個 19 字符的* ID 。 這樣設計,即可以保證生成的 ID 是有序的,也能方便閱讀。
如上圖所示,80 Bit 被分為 4 段:
1. *段 42 Bit ,用于存放時間戳,*長可表示到 2109 年,足夠*當前使用了。時間戳數(shù)據(jù)放在高位,可以保證生成的* ID 是按時間有序的,這個是消息 ID 必須要滿足的條件。
2. 第二段 12 Bit ,用于存放自旋轉 ID 。我們知道,時間戳的精度是到毫秒的,對于一套億級 IM 系統(tǒng)來說,同一毫秒內產生多條消息太正常不過了,這個自旋 ID 就是在給落到同一毫秒內的消息進行自增編號。12 Bit 則意味著,同一毫秒內,單臺主機中*多可以標識 4096( 2 的 12 次方)條消息。
3. 第三段 4 Bit ,用于標識會話類型。4 Bit ,*多可以標識 16 中會話,足夠涵蓋單聊、群聊、系統(tǒng)消息、聊天室、客服及公眾號等常用會話類型。
4. 第四段 22 Bit ,會話 ID 。如群聊中的群 ID ,聊天室中的聊天室 ID 等。與第三段會話類型組合在一起,可以*標識一個會話。其他的一些 ID 生成算法,會預留兩段,分別用來標識數(shù)據(jù)中心編號和主機編號(如 SnowFlake 算法),我們并沒有這樣做,而是將這兩段用來標識會話。這樣,ID 生成可以直接融入到業(yè)務服務中,且不必關心服務所在的主機,做到無狀態(tài)擴縮容。
?實現(xiàn)過程 ?
消息 ID 共占 80 Bit ,計算時我們分為兩部分,高 64 Bit (記為 highBits )和低 16 Bit (記為 lowBits )。
1. 獲取當前系統(tǒng)的時間戳,并賦值給消息 ID 的高 64 Bit ;
2. 獲取一個自旋 ID , highBits 左移 12 位,并將自旋 ID 拼接到低 12 位中;
其中,自旋 ID 是一個從 0 到 4095 范圍內,順序遞增的數(shù),生成規(guī)則如下:
3. 上步的 highBits 左移 4 位,將會話類型拼接到低 4 位;
4. 取會話 ID 哈希值的低 22 位,記為 sessionIdInt ;
5. highBits 左移 6 位,并將 sessionIdInt 的高 6 位拼接到 highBits 的低 6 位中;
6. 取會話 ID 的低 16 位作為 lowBits ;
7. highBits 與 lowBits 拼接,得到 80 Bit 的消息 ID 。對其進行 32 進制編碼,即可得到*消息 ID 。編碼規(guī)則如下:從左至右,每 5 個 Bit 轉換為一個整數(shù),以這個整數(shù)作為下標,即可在下表中找到對應的字符。
總結:
這種 ID 生成的方式,需要注意保證自旋 ID 的生成是線程安全的。避免在并發(fā)情況下,生成出同樣的 ID 。另外,此 ID 生成算法,強烈依賴系統(tǒng)時間,如果系統(tǒng)時間被改小,也可能造成 ID 生成重復。
申請創(chuàng)業(yè)報道,分享創(chuàng)業(yè)好點子。點擊此處,共同探討創(chuàng)業(yè)新機遇!