IM系統海量訊息資料是怎麼儲存的?
一、與訊息相關的主要場景
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)水平(取模Hash)分庫,存到一張表中(例如叫:msg_group)。核心欄位包括msgid(訊息ID),fromId(傳送者Id),groupId(群Id),content(訊息內容)。
另外一張msg_group_user表記錄使用者加入群的時間,如下圖。某個人(如張三)加入群的時間,相當於一個遊標,群訊息表中,這個遊標之後的聊天訊息,是這個人(張三)能夠檢視的資料(當然,也可以做檢視加入群之前若干條訊息)。
拉取群歷史訊息,直接倒序讀取這個群訊息表資料即可。
由於MySQL和Redis都採用了水平分庫,儲存能力幾乎可以線性擴充套件!是不是這樣就足夠了呢?答案是否定的,最佳化永遠沒有盡頭。如果我在非洲某個國家登入系統,從北京的機房讀取訊息資料顯然不太合適!如何讓資料靠近使用者,是一個更加有挑戰的問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556438/viewspace-2639412/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 訊息資料庫Message DB:PostgreSQL的事件儲存和訊息儲存 - Eventide Blog資料庫SQL事件IDE
- 什麼是大資料系統儲存及管理?大資料
- 海量資料儲存之動態SchemaOU
- 【RocketMQ】訊息的儲存MQ
- IM系統的MQ訊息中介軟體選型:Kafka還是RabbitMQ?MQKafka
- 資料儲存-領存高速海量資料記錄儲存模組產品介紹
- 杉巖海量物件儲存系統完美替代Documentum物件
- 杉巖海量資料儲存解決方案
- 海量資料監控如何選擇儲存方案? 看轉轉、得物這些企業是怎麼做的
- IM開發乾貨分享:淺談IM系統中離線訊息、歷史訊息的最佳實踐
- 什麼是YottaChain儲存,為什麼說是未來資料儲存的趨勢?AI
- 面向海量資料,一篇文章認識Ceph分散式儲存系統分散式
- 50億海量資料如何高效儲存和分析?
- 資料庫mysql儲存是什麼?可以存什麼?資料庫MySql
- MQ系列8:資料儲存,訊息佇列的高可用保障MQ佇列
- # MySQL server 層和儲存引擎層是怎麼互動資料的?MySqlServer儲存引擎
- 海量非結構化資料儲存難題 ,杉巖資料物件儲存完美解決物件
- MySQL 的 NULL 值是怎麼儲存的?MySqlNull
- EMQ X + IoTDB:儲存 MQTT 訊息到時序資料庫MQQT資料庫
- 海量資料的分頁怎麼破?
- 面對海量的監控影片資料應該如何儲存?
- Kafka 訊息儲存機制Kafka
- 大資料檔案儲存系統HDFS大資料
- RocketMQ的訊息是怎麼丟失的MQ
- 【儲存資料恢復】IBM儲存檔案NTFS系統損壞的資料恢復案例資料恢復IBM
- 如何降低複雜度,用資料庫做訊息佇列的儲存?複雜度資料庫佇列
- 一個海量線上使用者即時通訊系統(IM)的完整設計
- 資料庫mysql儲存遇到禁用怎麼辦?資料庫MySql
- 使用mongodb、Kafka儲存mqtt訊息MongoDBKafkaMQQT
- Kafka -- 訊息傳送儲存流程Kafka
- RocketMQ -- 訊息傳送儲存流程MQ
- 區塊鏈資訊儲存是如何實現安全儲存區塊鏈
- RocketMQ 原理:訊息儲存、高可用、訊息重試、訊息冪等性MQ
- MES系統是怎麼進行資料採集的?
- 分散式系統中的資料儲存方案實踐分散式
- 杉巖資料:海量智慧儲存,打造新基建數字底座
- 儲存系統
- 阿里IM技術分享(五):閒魚億級IM訊息系統的及時性優化實踐阿里優化