[即時通訊]千人羣組消息管理

消息時序

理想狀態下,客戶端和服務端數據是一致的。實際情況,涉及到用戶上線或下線。(詳見下圖)

  1. 用戶在線:服務實時發送消息。
  2. 用戶離線:服務保存消息;用戶重新上線後,向服務獲取離線消息。

消息時序


  1. 羣組離線消息數據(分頁獲取)。

    如上圖:client 每條消息都是有時序的,像鏈表一樣,串聯起來,每個 node 都可以通過 next 指向上一條消息:

    1. 如果上一條消息 msg_id 是 0,說明當前結點是第一條消息(如上圖 msg_id == 1 的消息)。
    2. 如果上一條消息 msg_id 不是 0,且消息存在於本地,那麼消息是連續的,不需要向服務同步(如上圖 msg_id == 2 的消息)。
    3. 如果上一條消息 msg_id 不是 0,但本地消息不存在,那麼需要向服務器獲取。(如上圖 msg_id == 9 的消息)。

    終端通過消息鏈表方式的檢查,很容易確認是否需要向服務同步數據。

  2. 羣組未讀消息總條數。

    從 client 的緩存中提取最新(lastest)的 msg_id,對應消息體有 recv_time。

    服務端消息的時序通過 redis 的 sortset 存儲的:

    key: group_id, score: recv_time, value: msg_id

    redis 的 sortset 結構,很容易通過一個 score 獲取一個區間的數據總數。


redis 設計

  1. sortset 存儲存儲消息時序

    key: group_id, score: recv_time, value: msg_id

  2. string 存儲消息體

    key: msg_id, value: msg_body

    因爲消息體數量較多,而且活躍時間比較短(因爲大部分用戶只關心最近接收的消息),所以把它獨立出來。便於 timeout 後 redis 能刪除節省內存。

  3. set 存儲未讀消息對象

    key: uid, member:group_id/send_uid

    每個用戶都可能有 N 個羣組,N 個好友。用戶重新上線後,不可能遍歷所有好友或羣組對象。所以服務在處理離線消息時,需要記錄未讀消息對象。


database 設計

  1. 羣組和羣組成員關係

    group_id, uid

  2. 消息結構

    msg_id, group_id, send_uid, recv_uid, recv_time, msg_body


服務存儲架構

im 即時通訊,服務是讀多寫少類型。服務端有三層存儲(如下圖),通過熱點數據的緩存,讓服務高效讀取。

  1. msg server 服務進程內存 session 緩存熱點數據。

緩存當前活躍的數據:頭像信息,用戶名稱,消息實體等數據,緩存一般 5 - 30 分鐘,根據具體的業務需要

  1. redis 第二層緩存熱點數據。

緩存大量的熱點數據,減少對 db 的訪問頻率,緩存時間相對較長,幾個月不等。

  1. database 數據落地。

存儲架構


數據讀寫時序

寫數據

寫邏輯

讀數據

讀邏輯


總結

基於以上分析,羣組消息,每個用戶發送的消息,不需要針對每個羣組成員都存一條到 database,否則千人羣組,每個成員存一條數據就是一千條,那麼消息的存儲就是個大坑。每個用戶發送消息 database 只需要存一條即可。通過多級緩存的架構,服務的性能一般體量的消息實時通訊是沒有問題的。當然這裏面還有很多細節問題需要在實際的業務場景中調優。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章