一個海量線上使用者即時通訊系統(IM)的完整設計
1 伺服器端設計
1.1 總體架構
總體架構包括5個層級,具體內容如下圖。
1.1.1 使用者端
移動端重點是移動端,支援IOS/Android系統,包括IM App,嵌入訊息功能的瓜子App,未來還可能接入客服系統。
1.1.2 使用者端API
針對TCP協議,提供IOS/Android開發SDK。對於H5頁面,提供WebSocket介面
1.1.3 接入層
接入層主要任務是保持海量使用者連線(接入)、攻擊防護、將海量連線整流成少量TCP連線與邏輯層通訊。
1.1.4 邏輯層
邏輯層負責IM系統各項功能的核心邏輯實現。包括單聊(c2c)、上報(c2s)、推送(s2c)、群聊(c2g)、離線訊息、登入授權、組織機構樹等等內容。
1.1.5 儲存層
儲存層負責快取或儲存IM系統相關資料,主要包括使用者狀態及路由(快取),訊息資料(MySQL也可採用NoSql,如MangoDB),檔案資料(檔案伺服器)。
1.2 邏輯結構
1.2.1 核心結構
核心結構部分描述IM系統核心元件及其關係。結構圖如下。
客戶端從Iplist服務獲取接入層IP地址(也可採用域名的方式解析得到接入層IP地址),建立與接入層的連線(可能為短連線),從而實現客戶端與IM伺服器的資料互動;業務線伺服器可以透過伺服器端API建立與IM伺服器的聯絡,向客戶端推送訊息;客戶端上報到業務伺服器的訊息,IM伺服器會透過mq投遞給業務伺服器。
1.2.2 tcp接入核心流程
1.2.2.1 登入授權(auth)
1、客戶端透過統一登入系統實現登入,得到token。
2、客戶端用uid和token向msg-gate發起授權驗證請求。
3、msg-gate同步呼叫msg-logic的驗證介面
4、msg-logic請求sso系統驗證token合法性
5、msg-gate得到登入結果後,設定session狀態,並向客戶端返回授權結果。
1.2.2.2 登出(logout)
1、客戶端發起logout請求,msg-gate設定對應Peer為未登入狀態。
2、Msg-gate給客戶端一個ack響應。
3、Msg-gate通知msg-logic使用者登出。
1.2.2.3踢人(kickout)
使用者請求授權時,可能在另一個裝置(同型別裝置)開著軟體處於登入狀態。這種情況需要系統將那個裝置踢下線。
1-5步,參看Auth流程。
6、Logic檢索Redis,檢視是否該使用者在其他地方登入。
7、如果在其他地方登入,發起kickout命令。(如果沒有登入,整個流程結束)
8、Gate向使用者發起kickout請求,並在短時間內(確保客戶端收到kickout資料)關閉socket連線。
1.2.2.4 上報(c2s)
1、客戶端向gate傳送資料
2、Gate回一個ack包,向客戶端確認已經收到資料
3、Gate將資料包傳遞給logic
4、Logic根據資料投遞目的地,選擇對應的mq佇列進行投遞
5、業務伺服器得到資料
1.2.2.5推送(s2c)
1、業務線呼叫push資料介面sendMsg
2、Logic向redis檢索目標使用者狀態。如果目標使用者不線上,丟棄資料(未來可根據業務場景定製化邏輯);如果使用者線上,查詢到使用者連線的接入層gate
3、Logic向使用者所在的gate傳送資料
4、Gate向使用者推送資料。(如果使用者不線上,通知logic使用者不線上)
5、客戶端收到資料後向gate傳送ack反饋
6、Gate將ack資訊傳遞給logic層,用於其他可能的邏輯處理(如日誌,確認送達等)
1.2.2.6單對單聊天(c2c)
1、App1向gate1傳送資訊(資訊最終要發給App2)
2、Gate1將資訊投遞給logic
3、Logic收到資訊後,將資訊進行儲存
4、儲存成功後,logic向gate1傳送ack
5、Gate1將ack資訊發給App1
6、Logic檢索redis,查詢App2狀態。如果App2未登入,流程結束
7、如果App2登入到了gate2,logic將訊息發往gate2
8、Gate2將訊息發給App2(如果發現App2不線上,丟棄訊息即可,這種機率極低,後續離線訊息可保證訊息不丟)
9、App2向gate2傳送ack
10、Gate2將ack資訊發給logic
11、Logic將訊息狀態設定為已送達。
注:在第6步和第7步之間,啟動計時器(DelayedQueue或雜湊環,時間如5秒),計時器時間到後,探測該條訊息狀態,如果訊息未送達,考慮透過APNS、米推、個推進行推送
1.2.2.7 群聊(c2g)
採用擴散寫(而非擴散讀)的方式。
群聊是多人社交的基本訴求,一個群友在群內發了一條訊息:
(1)線上的群友能第一時間收到訊息
(2)離線的群友能在登陸後收到訊息
由於“訊息風暴擴散係數”的存在,群訊息的複雜度要遠高於單對單訊息。
群基礎表:用來描述一個群的基本資訊
im_group_msgs(group_id, group_name,create_user, owner, announcement, create_time)
群成員表:用來描述一個群裡有多少成員
im_group_users(group_id, user_id)
使用者接收訊息表:用來描述一個使用者的所有收到群訊息(與單對單訊息表是同一個表)
im_message_recieve(msg_id,msg_from,msg_to, group_id,msg_seq, msg_content, send_time, msg_type, deliverd, cmd_id)
使用者傳送訊息表:用來描述一個使用者傳送了哪些訊息
im_message_send (msg_id,msg_from,msg_to, group_id,msg_seq, msg_content, send_time, msg_type, cmd_id)
業務場景舉例:
(1)一個群中有x,A,B,C,D共5個成員,成員x發了一個訊息
(2)成員A與B線上,期望實時收到訊息
(3)成員C與D離線,期望未來拉取到離線訊息
群聊流程如下圖所示
1、X向gate傳送資訊(資訊最終要發給這個群,A、B線上)
2、Gate將訊息發給logic
3、儲存訊息到im_message_send表,按照msg_from水平分庫
4、回ack
5、回ack
6、Logic檢索資料庫(需要使用快取),獲得群成員列表
7、儲存每個使用者的訊息資料(使用者檢視),按照msg_to水平分庫(併發、批次寫入)。
8、查詢使用者線上狀態及位置
9、Logic向gate投遞訊息
10、Gate向使用者投遞訊息
11、App返回收到訊息的ack資訊
12、Gate向logic傳遞ack資訊
13、向快取(Hash)中更新收到ack的時間。然後在透過一個定時任務,每隔一定時間,將資料更新到資料庫(注意只需要寫入時間段內有變化的資料)。
1.2.2.8拉取離線訊息
下圖中,將gate和logic合併為im-server。拉取離線訊息流程如下。
1、App端登入成功後(或業務觸發拉取離線訊息),向IM系統發起拉離線訊息請求。傳遞3個主要引數,uid表明使用者;msgid表明當前收到的最大訊息id(如果沒收到過訊息,或拿不到最大訊息id則msgid=0)即可;size表示每次拉取條數(這個值也可以由伺服器端控制)。
2、假設msgid==0,什麼都不做。(參看第6步驟)
3、Im-server查詢使用者前10條離線訊息
4、將離線訊息推給使用者。假設這10條離線訊息最大msgid=110。
5、App得到資料,判斷得到的資料不為空(表明可能沒有拉完離線資料,不用<10條做判斷拉完條件,因為服務端需要下下次拉離線的請求來確定這次資料已送達),繼續發起拉取操作。Msgid=110(取得到的離線訊息中最大的msgid)。
6、Im-server刪除該使用者msgid<110的離線訊息(或者標記為已送達)。
7、查詢msgid>110的錢10條離線資料。
8、返回給App
……
N-1、查詢msgid>140的離線資料,0條(沒有離線資料了)。
N 、將資料返回App,App判斷拉取到0條資料,結束離線拉取過程。
1.2.3 PUSH
ISO採用APNS;Android真後臺保活,同時增加米推、個推。
基本思路:push提示資訊,App透過拉離線獲得真實訊息。
另附文件說明此問題。
2 協議設計
2.1 TCP資料協議
TCP的資料協議如下圖所示。包括header和body兩部分。
訊息頭總共20個位元組,具體資訊如下表。
2.2TCP訊息體設計
訊息體協議採用ProtocolBuffer(谷歌)協議,版本3.0.0,該協議在序列化效率、壓縮、可擴充套件方面都具有優勢。協議條目見附錄11.1.1TCP協議命令清單。以下為主要流程涉及的協議
2.2.1 認證(auth)
2.2.2 登出(logout)
2.2.3 踢人(kickout)
2.2.4 心跳(keepalive,noop)
心跳包訊息體為空。
2.2.5單對單聊天(c2c)
2.2.6群聊(c2g)
2.2.7拉離線(pull)
2.2.8控制類(ctrl)
3 儲存設計
3.1MySQL資料庫
MySQL資料庫採用utf8mb4編碼格式(emoji字元問題)
3.1.1主要表結構
3.1.1.1傳送訊息表
儲存某個使用者傳送了哪些訊息,用於復現使用者聊天場景(訊息漫遊功能需要)。
3.1.1.2推送訊息表
儲存某個使用者收到了哪些訊息
3.1.1.3群相關表
群基本資訊表
群使用者關係表
3.1.2 水平分庫
3.2Redis快取
3.2.1使用者狀態及路由資訊
Redis快取以uid為key,檢索channel(socketid),last_packet_time等。
Gate層,session以channel(socketed)為key,檢索uid,及其他資訊。
互動介面:gate->logic,透過將channel轉換為uid作為key。
logic->gate,將uid轉換為channel作為key。
3.2.2其他快取資訊
你覺得該怎麼存就怎麼存。
3.3檔案及圖片儲存
採用商用雲端儲存。
3.4資料歸檔
可考慮採用HBase,HDFS作為資料歸檔,或者相關雲端儲存服務。
安全部分略,其他非核心功能略
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556438/viewspace-2637110/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- gochat - 純go實現的im即時通訊系統(支援水平擴充套件)Go套件
- 區塊鏈即時通訊系統開發,IM社交軟體開發app區塊鏈APP
- 區塊鏈IM聊天軟體開發,即時通訊系統搭建原始碼區塊鏈原始碼
- 基於XMPP的即時通訊系統的建立(三)— 程式設計概覽程式設計
- 企業社交直播軟體開發,區塊鏈IM即時通訊系統開發區塊鏈
- 區塊鏈即時通訊系統開發原始碼,IM社交軟體開發app區塊鏈原始碼APP
- 為自己搭建一個分散式 IM(即時通訊) 系統分散式
- 「實戰」搭建完整的IM(即時通訊)應用(2)
- 「實戰」搭建完整的IM(即時通訊)應用(1)
- 基於XMPP的即時通訊系統的建立(一)— XMPP基礎概念
- 即時通訊系統中實現全域性系統通知,並與Web後臺整合【附C#開源即時通訊系統(支援廣域網)——QQ高仿版IM最新原始碼】WebC#原始碼
- DAPP即時通訊系統開發(詳細案例)丨DAPP即時通訊系統開發(方案規則)/原始碼APP原始碼
- 這套分散式IM即時通訊系統如何寫到簡歷上?我給你整理好了!分散式
- 即時通訊系統為什麼選擇GaussDB(for Redis)?Redis
- 採用spark和openfire實現即時通訊系統Spark
- DAPP區塊鏈即時通訊系統開發(功能詳情)丨DAPP即時通訊系統開發(原始碼專案)APP區塊鏈原始碼
- 即時通訊系統是企業提高辦公效率的利器
- 基於XMPP的即時通訊系統的建立(二)— XMPP詳解
- [內推]有想用Go寫一個世界級的政務金融行業即時通訊系統 歡迎聯絡我哈~ 急!線上等!Go行業
- 企業內部即時通訊系統專案總結
- SIMULIA的飛機通訊系統設計
- 基於XMPP的即時通訊系統的建立(四)— 協議詳解協議
- 急急如律令!火速搭建一個C#即時通訊系統!(附原始碼分享——高度可移植!)C#原始碼
- 即時聊天(IM)儲存方案
- 基於XMPP協議的Android即時通訊系協議Android
- 線上客服系統原始碼-開源PHP版(開源im即時通訊原始碼)原始碼PHP
- Spring Boot 開發整合 WebSocket,實現私有即時通訊系統Spring BootWeb
- 基於Netty,徒手擼IM(一):IM系統設計篇Netty
- 區塊鏈IM社交系統開發,IM即時通訊平臺搭建app區塊鏈APP
- 原生JAVA即時通訊系統原始碼語音視訊聊天軟體Java原始碼
- [轉載]淺析海量使用者的分散式系統設計分散式
- 極速、便捷!一個接入 AI 的匿名線上即時聊天室!AI
- 極光的開源禮物「Aurora IMUI」一個通用的即時通訊(IM)UI 庫UI
- 區塊鏈社交即時通訊系統開發方案,區塊鏈系統開發區塊鏈
- 區塊鏈社交直播軟體開發app,即時通訊系統開發區塊鏈APP
- socket.io和node.js搭建即時通訊系統簡答介紹Node.js
- 不用下載線上就能設計詳情頁的工具,海量模板一鍵用!
- 完整的設計一個專案需要什麼?