本文來自融雲技術團隊原創分享,原文發佈於「融雲全球互聯網通訊雲」公衆號,原題《如何實現分佈式場景下惟一 ID 生成?》,即時通信網收錄時有部分改動。php
對於IM應用來講,消息ID(或稱序列號)是個看似不起眼,但很是重要的東西之一。html
消息ID的使用貫穿了IM技術邏輯的方方面面,好比:web
1)聊天消息的順序保證;算法
2)聊天消息QoS送達保證機制時的去重;瀏覽器
3)特定聊天消息的精確查找和匹配;安全
4)聊天消息的已讀未讀處理;微信
5)聊天消息的送達回執;網絡
6)羣聊消息的擴散讀拉取標記;session
7)... ...架構
但,IM系統高度個性化的特性(設計上沒有統一的標準和思路),包括聊天消息ID的生成算法在內,每一個產品都有自已的思路和考量。
常見的消息ID生成策略有:
1)UUID:這種方法簡單直觀,能夠很好的保證惟一性,但對於技術潔癖的人來講ID長度會有點長;
2)使用時間戳長整數:這個最偷懶,用在吞吐量不大的場景下,湊活也能用,但存在重複的風險,也沒法保證分佈式下的惟一性;
3)使用twitter開源的snowflake算法:在分佈式高併發的狀況下,這也是個不錯的選擇;
4)按用戶使用獨立的ID生成空間生成順序的ID:好比微信的消息序列號生成策略就很不錯。
從某種意義上來說,消息ID的生成策略決定了IM應用層某些功能實現的難易度,好的消息ID生成策略會讓IM產品的開發越作越順,反之越作越彆扭。
本文要分享的是融雲即時通信雲產品中的聊天消息ID生成算法和策略,一個19字節的ID就能包含:時間戳、消息類型、會話ID、序列號,小ID、大用途,值得借鑑!
免責申明:本文來自融雲官方技術團隊的分享,僅用於技術交流學習和研究目的,請勿用於非法用途,文中如涉及商業祕密,請告之我處理!
特別說明:僅出於技術研究和學習目的來分享此文,並未收取任何好處,因此此文不是廣告,我也不是託。若有不妥,請告之!
學習交流:
- 即時通信/推送技術開發交流5羣:215477170[推薦]
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
(本文同步發佈於:http://www.52im.net/thread-2747-1-1.html)
對於一套分佈式部署的 IM 系統,要求每條消息的 ID 要保證在集羣中全局惟一且按生成時間有序排列。如何快速高效的生成消息數據的惟一 ID ,是影響系統吞吐量的關鍵因素。
那麼,融雲是如何作到生成全局惟一消息 ID 的呢?
首先須要明確下 ID 生成的核心需求:
1)全局惟一;
2)有序。
融雲消息數據的惟一 ID 長度採用 80 Bit。
每 5 個 Bit ,進行一次 32 進制編碼,轉換爲一個字符,字符取值範圍是:數字 「2 ~ 9 」和字母「A ~ B」。其中,已經去掉容易形成肉眼混淆的,數字 0 和 1 (餘下可用的數字是8個),及字母 O 和 I(餘下可用的字母是24個),總可用字符就是32個(恰好可按32進制進行編碼)。
這樣,80 Bit 能夠轉換爲 16 個字符,再加上 3 個分隔符( - ),將 16 個字符分爲 4 組,最終獲得一個 19 字符的惟一 ID ,形如:「 BD8U-FCOJ-LDC5-L789 」。 這樣設計,便可以保證生成的 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)。
具體的代碼實現過程,大體以下。
1)獲取當前系統的時間戳,並賦值給消息 ID 的高 64 Bit :
2)獲取一個自旋 ID , highBits 左移 12 位,並將自旋 ID 拼接到低 12 位中:
其中,自旋 ID 是一個從 0 到 4095 範圍內,順序遞增的數,生成規則以下:
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:
編碼規則:從左至右,每 5 個 Bit 轉換爲一個整數,以這個整數做爲下標,便可在下表中找到對應的字符。
PS:若是感受上面兩節介紹的算法思路和代碼實現有點抽象,能夠直接去看融雲的IM產品中的實際消息ID生成狀況。
好比,從融雲的Demo產品中取出的同一個用戶相近時間內的3條單聊消息ID樣本:
BD8U-DG1U-5UI5-L789
BD8U-DU6D-2205-L789
BD8U-FCOJ-LDC5-L789
好比,能夠直接登錄融雲的Web產品 http://web.sealtalk.im,在瀏覽器端研究學習它的消息ID生成狀況:
特別說明:僅僅出於技術研究和學習目的來分享此文,並無收到融雲的任何好處,因此此文不是廣告,我也不是託。若有不妥,請告之!
融雲所使用的這種 ID 生成的方式,須要注意:
1)注意保證自旋 ID 的生成是線程安全的;
2)避免在併發狀況下,生成出一樣的 ID ;
3)此 ID 生成算法,強烈依賴系統時間,若是系統時間被改小,也可能形成 ID 生成重複。
《新手入門一篇就夠:從零開發移動端IM》
《移動端IM開發者必讀(一):通俗易懂,理解移動網絡的「弱」和「慢」》
《移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結》
《從客戶端的角度來談談移動端IM的消息可靠性和送達機制》
《現代移動端網絡短鏈接的優化手段總結:請求速度、弱網適應、安全保障》
《騰訊技術分享:社交網絡圖片的帶寬壓縮技術演進之路》
《小白必讀:閒話HTTP短鏈接中的Session和Token》
《IM開發基礎知識補課:正確理解前置HTTP SSO單點登錄接口的原理》
《移動端IM中大規模羣消息的推送如何保證效率、實時性?》
《移動端IM開發須要面對的技術問題》
《開發IM是本身設計協議用字節流好仍是字符流好?》
《請問有人知道語音留言聊天的主流實現方式嗎?》
《IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》
《IM消息送達保證機制實現(二):保證離線消息的可靠投遞》
《如何保證IM實時消息的「時序性」與「一致性」?》
《一個低成本確保IM消息時序的方法探討》
《IM單聊和羣聊中的在線狀態同步應該用「推」仍是「拉」?》
《IM羣聊消息如此複雜,如何保證不丟不重?》
《談談移動端 IM 開發中登陸請求的優化》
《移動端IM登陸時拉取數據如何做到省流量?》
《淺談移動端IM的多點登錄和消息漫遊原理》
《徹底自已開發的IM該如何設計「失敗重試」機制?》
《通俗易懂:基於集羣的移動端IM接入層負載均衡方案分享》
《微信對網絡影響的技術試驗及分析(論文全文)》
《即時通信系統的原理、技術和應用(技術論文)》
《開源IM工程「蘑菇街TeamTalk」的現狀:一場虎頭蛇尾的開源秀》
《騰訊原創分享(一):如何大幅提高移動網絡下手機QQ的圖片傳輸速度和成功率》
《如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源》
《基於社交網絡的Yelp是如何實現海量用戶圖片的無損壓縮的?》
《騰訊技術分享:騰訊是如何大幅下降帶寬和網絡流量的(圖片壓縮篇)》
《騰訊技術分享:騰訊是如何大幅下降帶寬和網絡流量的(音視頻技術篇)》
《字符編碼那點事:快速理解ASCII、Unicode、GBK和UTF-8》
《全面掌握移動端主流圖片格式的特色、性能、調優等》
《子彈短信光鮮的背後:網易雲信首席架構師分享億級IM平臺的技術實踐》
《IM開發基礎知識補課(五):通俗易懂,正確理解並用好MQ消息隊列》
《微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)》
《自已開發IM有那麼難嗎?手把手教你自擼一個Andriod版簡易IM (有源碼)》
《融雲技術分享:解密融雲IM產品的聊天消息ID生成策略》
>> 更多同類文章 ……
(本文同步發佈於:http://www.52im.net/thread-2747-1-1.html)