好消息:IM1.0.0版本已經上線啦,支持特性:mysql
首先講講IM(即時通信)技術能夠用來作什麼:
聊天:qq、微信
直播:鬥魚直播、抖音
實時位置共享、遊戲多人互動等等
能夠說幾乎全部高實時性的應用場景都須要用到IM技術。git
本篇將帶你們從零開始搭建一個輕量級的IM服務端,麻雀雖小,五臟俱全,咱們搭建的IM服務端實現如下功能:github
這個項目涵蓋了不少後端必備知識:redis
咱們先從最簡單的特性開始實現:一個普通消息的發送
消息格式以下:sql
message ChatMsg{
id = 1;
//消息id
fromId = Alice
//發送者userId
destId = Bob
//接收者userId
msgBody = hello
//消息體
}
複製代碼
message(hello)
給Bob,服務端接收到消息,根據消息的destId進行轉發,轉發給Bob。
那咱們要怎麼來實現回執的發送呢?
咱們定義一種回執數據格式ACK,MsgType有三種,分別是sent
(已發送),delivered
(已送達), read
(已讀):docker
message AckMsg {
id;
//消息id
fromId;
//發送者id
destId;
//接收者id
msgType;
//消息類型
ackMsgId;
//確認的消息id
}
enum MsgType {
DELIVERED;
READ;
}
複製代碼
當服務端接受到Alice發來的消息時:數據庫
sent(hello)
表示消息已經被髮送到服務器。message AckMsg {
id = 2;
fromId = Alice;
destId = Bob;
msgType = SENT;
ackMsgId = 1;
}
複製代碼
hello
轉發給Bob後,馬上向Alice發送
delivered(hello)
表示消息已經發送給Bob。
message AckMsg {
id = 3;
fromId = Bob;
destId = Alice;
msgType = DELIVERED;
ackMsgId = 1;
}
複製代碼
read(hello)
表示消息已讀
message AckMsg {
id = 4;
fromId = Bob;
destId = Alice;
msgType = READ;
ackMsgId = 1;
}
複製代碼
這個消息會像一個普通聊天消息同樣被服務器處理,最終發送給Alice。 後端
在服務器這裏不區分ChatMsg
和AckMsg
,處理過程都是同樣的:解析消息的destId
並進行轉發。緩存
當用戶量愈來愈大,必然須要增長服務器的數量,用戶的鏈接被分散在不一樣的機器上。此時,就須要存儲用戶鏈接在哪臺機器上。
咱們引入一個新的模塊來管理用戶的鏈接信息。安全
模塊叫作user status
,共有三個接口:
public interface UserStatusService {
/**
* 用戶上線,存儲userId與機器id的關係
*
* @param userId
* @param connectorId
* @return 若是當前用戶在線,則返回他鏈接的機器id,不然返回null
*/
String online(String userId, String connectorId);
/**
* 用戶下線
*
* @param userId
*/
void offline(String userId);
/**
* 經過用戶id查找他當前鏈接的機器id
*
* @param userId
* @return
*/
String getConnectorId(String userId);
}
複製代碼
這樣咱們就可以對用戶鏈接狀態進行管理了,具體的實現應考慮服務的用戶量、指望性能等進行實現。
此處咱們使用redis來實現,將userId和connectorId的關係以key-value的形式存儲。
除此以外,還須要一個模塊在不一樣的機器上轉發消息,以下結構:
此時咱們的服務被拆分紅了connector
和transfer
兩個模塊,connector
模塊用於維持用戶的長連接,而transfer
的做用是將消息在多個connector
之間轉發。
如今Alice和Bob鏈接到了兩臺connector上,那麼消息要如何傳遞呢?
機器[1]
上時
user status
的online
方法記錄Alice上線。機器[1]
收到消息後,解析destId,在內存中查找是否有Bob。transfer
。transfer
調用user status
的getConnectorId(Bob)
方法找到Bob所鏈接的connector,返回機器[2]
,則轉發給機器[2]
。流程圖:
user status
模塊管理用戶鏈接,transfer
模塊在不一樣的機器之間轉發,使服務能夠水平擴展。transfer
須要和每臺connector
機器都保持長連接。若是用戶當前不在線,就必須把消息持久化下來,等待用戶下次上線再推送,這裏使用mysql存儲離線消息。
爲了方便地水平擴展,咱們使用消息隊列進行解耦。
transfer
接收到消息後若是發現用戶不在線,就發送給消息隊列入庫。用戶的註冊登陸、帳戶管理、好友關係鏈等功能更適合使用http協議,所以咱們將這個模塊作成一個restful服務,對外暴露http接口供客戶端調用。
至此服務端的基本架構就完成了:
以上就是這篇博客的全部內容,本篇幫你們構建了IM服務端的架構,但還有不少細節須要咱們去思考,例如:
更多細節實現就留到下一篇啦~
IM1.0.0版本已上線,github連接: github.com/yuanrw/IM
以爲對你有幫助請點個star吧~!