【融雲分析】如何實現分佈式場景下惟一 ID 生成?

圖片描述

◀背景▶算法

對於一套分佈式部署的 IM 系統,要求每條消息的 ID 要保證在集羣中全局惟一且按生成時間有序排列。如何快速高效的生成消息數據的惟一 ID ,是影響系統吞吐量的關鍵因素。那麼,融雲是如何作到生成全局惟一消息 ID 的呢?安全

首先須要明確下 ID 生成的核心需求:session

  1. 全局惟一
  2. 有序

◀設計▶併發

融雲消息數據的惟一 ID 長度採用 80 Bit 。每 5 個 Bit ,進行一次 32 進制編碼,轉換爲一個字符,字符取值範圍是,( 2 ~ 9 ) 和 ( A ~ B ),其中,已經去掉容易形成肉眼混淆的,數字 0 和 1 ,及字母 O 和 I 。這樣,80 Bit 能夠轉換爲 16 個字符,再加上 3 個分隔符( - ),將 16 個字符分爲 4 組,最終獲得一個 19 字符的惟一 ID 。 這樣設計,便可以保證生成的 ID 是有序的,也能方便閱讀。
圖片描述
如上圖所示,80 Bit 被分爲 4 段:分佈式

  1. 第一段 42 Bit ,用於存放時間戳,最長可表示到 2109 年,足夠開發者當前使用了。時間戳數據放在高位,能夠保證生成的惟一 ID 是按時間有序的,這個是消息 ID 必需要知足的條件。
  2. 第二段 12 Bit ,用於存放自旋轉 ID 。咱們知道,時間戳的精度是到毫秒的,對於一套億級 IM 系統來講,同一毫秒內產生多條消息太正常不過了,這個自旋 ID 就是在給落到同一毫秒內的消息進行自增編號。12 Bit 則意味着,同一毫秒內,單臺主機中最多能夠標識 4096( 2 的 12 次方)條消息。
  3. 第三段 4 Bit ,用於標識會話類型。4 Bit ,最多能夠標識 16 中會話,足夠涵蓋單聊、羣聊、系統消息、聊天室、客服及公衆號等經常使用會話類型。
  4. 第四段 22 Bit ,會話 ID 。如羣聊中的羣 ID ,聊天室中的聊天室 ID 等。與第三段會話類型組合在一塊兒,能夠惟一標識一個會話。其餘的一些 ID 生成算法,會預留兩段,分別用來標識數據中心編號和主機編號(如 SnowFlake 算法),咱們並無這樣作,而是將這兩段用來標識會話。這樣,ID 生成能夠直接融入到業務服務中,且沒必要關心服務所在的主機,作到無狀態擴縮容。

◀實現過程▶編碼

消息 ID 共佔 80 Bit ,計算時咱們分爲兩部分,高 64 Bit (記爲 highBits )和低 16 Bit (記爲 lowBits )。spa

  1. 獲取當前系統的時間戳,並賦值給消息 ID 的高 64 Bit ;

圖片描述

  1. 獲取一個自旋 ID , highBits 左移 12 位,並將自旋 ID 拼接到低 12 位中;

圖片描述

其中,自旋 ID 是一個從 0 到 4095 範圍內,順序遞增的數,生成規則以下:
圖片描述線程

  1. 上步的 highBits 左移 4 位,將會話類型拼接到低 4 位;

圖片描述

  1. 取會話 ID 哈希值的低 22 位,記爲 sessionIdInt ;

圖片描述

  1. highBits 左移 6 位,並將 sessionIdInt 的高 6 位拼接到 highBits 的低 6 位中;

圖片描述

  1. 取會話 ID 的低 16 位做爲 lowBits ;

圖片描述

  1. highBits 與 lowBits 拼接,獲得 80 Bit 的消息 ID 。對其進行 32 進制編碼,便可獲得惟一消息 ID 。編碼規則以下:從左至右,每 5 個 Bit 轉換爲一個整數,以這個整數做爲下標,便可在下表中找到對應的字符。

圖片描述

總結:設計

這種 ID 生成的方式,須要注意保證自旋 ID 的生成是線程安全的。避免在併發狀況下,生成出一樣的 ID 。另外,此 ID 生成算法,強烈依賴系統時間,若是系統時間被改小,也可能形成 ID 生成重複。圖片

相關文章
相關標籤/搜索