一、與消息相關的主要場景

1、存儲和離線消息。

現在的IM系統,消息都要落地存儲。這樣如果接收消息的用戶不在線,等他下次上線時,能獲取到消息數據。

2、消息漫遊

消息漫遊包括主要兩種場景,

(1)用戶新安裝IM軟件,要能看到以前的聊天記錄

(2)聊天軟件有PC版和App版,在App上聊的天,打開PC版要能夠看到

二、不同場景讀取消息關鍵點

1、拉取離線消息

每個用戶打開App就需要拉取離線,網絡中斷重連後要拉取離線,收到消息序列號不連續也要拉取離線,拉取離線消息是一個高頻操作 。離線消息包括單聊、羣聊、控制類等消息,消息類型類型衆多。因此離線消息需要以用戶ID(多端情況下需要以端)爲檢索維度。說的直白一點,就是每個人 (端)都需要一個收件箱,拉離線消息就是把個人(端)收件箱裏的消息取到客戶端。

2、消息漫遊

消息漫遊的典型使用場景是,打開某個會話(單聊、羣聊、公衆號),下拉界面,客戶端向服務端請求這個會話的聊天數據。消息漫遊需要以會話爲檢索維度。消息漫遊拉取數據的頻率相對較低。我們把這類獲取消息的方式成爲拉取歷史消息。

三、存儲消息關鍵點

1、離線消息

離線消息讀取頻繁(寫也有一定壓力),但是檢索邏輯簡單(參看《一個海量在線用戶即時通訊系統(IM)的完整設計》拉取離線消息章節)。我們採用內存數據庫(Redis)存儲,主要結構使用SortedSet(可以有更高效的存儲結構,但Redis不支持)。對於羣消息,採用擴散寫方式(一條羣消息 給每個羣成員都寫一份)。按照消息接受者ID水平分庫。

2、歷史消息

歷史消息的訪問頻率低,但是每條消息都需要存儲,我們採用關係型數據庫(MySQL)存儲,重點考慮寫入效率。對於羣消息,採用擴散讀方式(每條羣消息只寫一條記錄)。按照消息發送者ID(單聊),或羣ID(羣聊)進行水平分庫。

四、消息存取方案

1、離線消息

存儲離線消息。按照消息接收者ID(toID),取模Hash分庫(也可以用一致性Hash)。每個用戶創建一個SortedSet結構的Key, 用於存儲離線消息。離線消息按照時間先後順序排列即可。SortedSet添加一個元素時間複雜度是O(log(N)),N 是有序集的基數,由於離線消息的msgid是有序的,所以實際插入時間複雜度很可能退化爲O(1)。

讀取離線消息。離線消息讀取策略參看《一個海量在線用戶即時通訊系統(IM)的完整設計》拉取離線消息章節。理論上讀取離線消息的時間複雜度爲O(log(N)+M), N 爲離線消息的條數, M 爲一次讀取消息的條數。實際上,由於離線消息從有序集的頭部開始讀取,實際時間複雜度比這個值低。

2、歷史消息

歷史消息分爲兩大類,單聊消息、羣聊消息。

單聊消息按照發送者ID(fromId)水平(取模Hash)分庫,存到一張數據表(例如叫msg_user_send)中。核心字段包括msgid(消息ID),fromId(發送者Id),toId(接收者Id),content(消息內容)。

拉取單聊歷史消息時(假設拉取userId1跟userId2的聊天),分別讀取兩人給對方發送的消息(因爲分庫原因,兩人發送的消息可能分佈在不同數據庫中),然後進行Merge。

羣聊消息按照羣ID(groupId

查看原文 >>
相關文章