一個海量線上使用者即時通訊系統(IM)的完整設計

普通程式設計師發表於2019-02-27

一個海量線上使用者即時通訊系統(IM)的完整設計

1 伺服器端設計

1.1 總體架構

總體架構包括5個層級,具體內容如下圖。

一個海量線上使用者即時通訊系統(IM)的完整設計

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系統核心元件及其關係。結構圖如下。

一個海量線上使用者即時通訊系統(IM)的完整設計


客戶端從Iplist服務獲取接入層IP地址(也可採用域名的方式解析得到接入層IP地址),建立與接入層的連線(可能為短連線),從而實現客戶端與IM伺服器的資料互動;業務線伺服器可以透過伺服器端API建立與IM伺服器的聯絡,向客戶端推送訊息;客戶端上報到業務伺服器的訊息,IM伺服器會透過mq投遞給業務伺服器。

1.2.2 tcp接入核心流程

1.2.2.1 登入授權(auth)

一個海量線上使用者即時通訊系統(IM)的完整設計

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)

一個海量線上使用者即時通訊系統(IM)的完整設計

1、客戶端發起logout請求,msg-gate設定對應Peer為未登入狀態。

2、Msg-gate給客戶端一個ack響應。

3、Msg-gate通知msg-logic使用者登出。

1.2.2.3踢人(kickout)

使用者請求授權時,可能在另一個裝置(同型別裝置)開著軟體處於登入狀態。這種情況需要系統將那個裝置踢下線。

一個海量線上使用者即時通訊系統(IM)的完整設計

1-5步,參看Auth流程。

6、Logic檢索Redis,檢視是否該使用者在其他地方登入。

7、如果在其他地方登入,發起kickout命令。(如果沒有登入,整個流程結束)

8、Gate向使用者發起kickout請求,並在短時間內(確保客戶端收到kickout資料)關閉socket連線。

1.2.2.4 上報(c2s)

 

一個海量線上使用者即時通訊系統(IM)的完整設計

1、客戶端向gate傳送資料

2、Gate回一個ack包,向客戶端確認已經收到資料

3、Gate將資料包傳遞給logic

4、Logic根據資料投遞目的地,選擇對應的mq佇列進行投遞

5、業務伺服器得到資料

1.2.2.5推送(s2c)

一個海量線上使用者即時通訊系統(IM)的完整設計

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)

一個海量線上使用者即時通訊系統(IM)的完整設計

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離線,期望未來拉取到離線訊息

群聊流程如下圖所示

一個海量線上使用者即時通訊系統(IM)的完整設計

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。拉取離線訊息流程如下。 一個海量線上使用者即時通訊系統(IM)的完整設計

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兩部分。

一個海量線上使用者即時通訊系統(IM)的完整設計

訊息頭總共20個位元組,具體資訊如下表。

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2TCP訊息體設計

訊息體協議採用ProtocolBuffer(谷歌)協議,版本3.0.0,該協議在序列化效率、壓縮、可擴充套件方面都具有優勢。協議條目見附錄11.1.1TCP協議命令清單。以下為主要流程涉及的協議

2.2.1 認證(auth) 

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2.2 登出(logout) 

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2.3 踢人(kickout) 

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2.4 心跳(keepalive,noop)

心跳包訊息體為空。

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2.5單對單聊天(c2c) 

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2.6群聊(c2g)

一個海量線上使用者即時通訊系統(IM)的完整設計

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2.7拉離線(pull)

一個海量線上使用者即時通訊系統(IM)的完整設計

2.2.8控制類(ctrl)

 一個海量線上使用者即時通訊系統(IM)的完整設計

一個海量線上使用者即時通訊系統(IM)的完整設計

3 儲存設計

3.1MySQL資料庫

MySQL資料庫採用utf8mb4編碼格式(emoji字元問題)

3.1.1主要表結構

3.1.1.1傳送訊息表

儲存某個使用者傳送了哪些訊息,用於復現使用者聊天場景(訊息漫遊功能需要)。

一個海量線上使用者即時通訊系統(IM)的完整設計

3.1.1.2推送訊息表

儲存某個使用者收到了哪些訊息

一個海量線上使用者即時通訊系統(IM)的完整設計

3.1.1.3群相關表

群基本資訊表

一個海量線上使用者即時通訊系統(IM)的完整設計

群使用者關係表

一個海量線上使用者即時通訊系統(IM)的完整設計

3.1.2 水平分庫

一個海量線上使用者即時通訊系統(IM)的完整設計

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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章