本文由融雲技術團隊原創分享,原題「IM 消息同步機制全面解析」,爲使文章更好理解,對內容進行了從新概括和細節修訂。html
即時通信(IM)系統最基礎、最重要的是消息的及時性與準確性,及時體如今延遲,準確則具體表現爲不丟、不重、不亂序。緩存
綜合考慮業務場景、系統複雜度、網絡流量、終端能耗等,咱們的億級分佈式IM消息系統精心設計了消息收發機制,並不斷打磨優化,造成了如今的消息可靠投遞機制。服務器
總體思路就是:markdown
本文根據融雲億級IM消息系統的技術實踐,總結了分佈式IM消息的可靠投遞機制,但願能爲你的IM開發和知識學習起到拋磚引玉的做用。網絡
一個完整的IM消息交互邏輯,一般會爲兩段:架構
消息上行段主要就是依賴IM的實時通道將消息傳遞給服務端。分佈式
這個階段的消息可靠投遞,須要從協議層進行保證,協議層須要提供可靠、有序的雙向字節流傳輸,咱們是經過自研的通訊協議 RMTP(即 RongCloud Message Transfer Protocol)實現的。oop
客戶端與服務端之間使用長鏈接,基於 RMTP 協議傳輸數據。性能
RMTP協議交互示意圖:學習
如上圖所示,協議層經過 QoS、 ACK 等機制,保證IM消息上行段數據傳輸的可靠性。
通過總結,消息下行段主要有三種行爲。
1)客戶端主動拉取消息,主動拉取有兩個觸發方式:
2)服務端主動-發送消息(直髮消息):
這是在線消息發送機制之一,簡單理解爲服務端將消息內容直接發送給客戶端,適用於消息頻率較低,而且持續交互,好比二人或者羣內的正常交流討論。
3)服務端主動-發送通知(通知拉取):
這是在線消息發送機制之一,簡單理解爲服務端給客戶端發送一個通知,通知包含時間戳等可做爲排序索引的內容,客戶端收到通知後,依據自身數據,對比通知內時間戳,發起拉取消息的流程。
這種場景適用於較多消息傳遞: 好比某人有不少大規模的羣,每一個羣內都有不少成員正在激烈討論。經過通知拉取機制,能夠有效的減小客戶端服務端網絡交互次數,而且對多條消息進行打包,提高有效數據載荷。既能保證時效,又能保證性能。
客戶端服務端下行段消息交互示意圖:
正如上節所言,咱們將消息的交互流程進行了拆分:即拆分出上下行。
在上行過程保證發送消息順序,爲了保證消息有序, 最好的方式是按照 userId 區分,而後使用時間戳排序。那麼分佈式部署狀況下,將用戶歸屬到固定的業務服務器上(PS:指的是同一帳號的不一樣端固定鏈接到相同的業務服務器上),會使得上行排序變得更容易。同時歸屬到同一個服務器,在多端維護時也更容易。
客戶端鏈接過程:
示意圖以下:
小結一下就是: 客戶端發出消息後,經過接入服務,按照 userId 投遞到指定消息服務器,生成消息 Id, 依據最後一條消息時間,確認更新當前消息的時間戳(若是存在相同時間戳則後延)。而後將時間戳,以及消息 Id,經過 Ack 返回給客戶端 ; 而後對上行消息使用 userId + 時間戳進行緩存以及持久化存儲,後續業務操做均使用此時間戳。
以上業務流程咱們稱爲上行流程,上行過程存儲的消息爲發件箱消息。
PS: 關於消息ID,須要補充說明一下:
咱們採用全局惟一的消息 ID 生成策略。保證消息可經過 ID 進行識別,排重。消息ID的結構以下圖所示。
如何實現分佈式場景下惟一 ID 生成,具體請閱讀:《IM消息ID技術專題(三):解密融雲IM產品的聊天消息ID生成策略》。
消息節點在處理完上行流程後,消息按照目標用戶投遞到所在消息節點,進入下行流程。
下行過程,按照目標 userId 以及本消息在上行過程當中生成的時間戳,計算是否須要更新時間戳(正向)。
若是須要更新則對時間戳進行加法操做,直到當前用戶時間戳不重複。
如此處理後,目標用戶的存儲以及客戶端接收到消息後的排重能夠作到一致,而且能夠作到同一個會話內的時間戳是有序的。從而保證同一個接收用戶的消息不會出現亂序。
至此: 咱們已經介紹完了消息的下行交互過程,消息下行過程當中的具體實現方式並不簡單,如下將詳細展開。
1)直髮消息:
即服務端主動發送(給目標客戶端)的消息:
直髮邏輯示意圖:
2)通知拉取:
即服務端主動發送通知(給目標客戶端):
示意圖:
在上圖中,3-7 步可能須要循環屢次,有如下考慮:
3)服務端直髮消息與通知拉取切換邏輯:
主要涉及到的是狀態機的更新。
下面示意圖集成直髮消息與通知拉取過程針對狀態機的更新:
至此,消息收發的整個核心流程介紹完畢,餘下的內容將介紹多端在線的消息同步處理。
多端按照消息的上下行兩個階段,一樣區分爲發送方多端同步以及接收方多端同步。
在前面客戶端鏈接 IM 服務過程當中(見本文 4.1節),咱們已經將同一個用戶的多個客戶端匯聚在了同一臺服務,那麼維護一個 userId 的多端就會變得很簡單。
具體邏輯是:
針對上面的第2)點,發送方的多端同步沒有通過 IM Server,這麼作的好處是:
具體邏輯是:
接收方多端消息同步範圍的應用場景,通常都是針對全部終端。
但有一些特殊業務: 好比我在 A 客戶端上,控制另外某個端的狀態,可能須要一些命令消息, 這時候須要這個做用範圍,針對性的投遞消息。
到此,咱們分享完了有關 IM 消息核心處理流程,經過層層拆解邏輯,提供了可靠的消息投遞機制。(本文已同步發佈於:www.52im.net/thread-3638…)
[1]《零基礎IM開發入門(二):什麼是IM系統的實時性?》
[2]《零基礎IM開發入門(三):什麼是IM系統的可靠性?》
[3]《零基礎IM開發入門(四):什麼是IM系統的消息時序一致性?》
[4]《IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》
[5]《IM消息送達保證機制實現(二):保證離線消息的可靠投遞》
[6]《IM開發乾貨分享:如何優雅的實現大量離線消息的可靠投遞》
[7]《理解IM消息「可靠性」和「一致性」問題,以及解決方案探討》
[8]《如何保證IM實時消息的「時序性」與「一致性」?》
[9]《IM羣聊消息如此複雜,如何保證不丟不重?》
[10]《從客戶端的角度來談談移動端IM的消息可靠性和送達機制》
[11]《一套億級用戶的IM架構技術乾貨(下篇):可靠性、有序性、弱網優化等》
如下是融雲技術團隊分享的其它文章:
[1]《IM消息ID技術專題(三):解密融雲IM產品的聊天消息ID生成策略》
[2]《融雲技術分享:基於WebRTC的實時音視頻首幀顯示時間優化實踐》
[3]《融雲技術分享:融雲安卓端IM產品的網絡鏈路保活技術實踐》