云南網(wǎng)站建設(shè)專家百度搜索大全
基于 http 短輪詢模式的單體架構(gòu)的 IM 系統(tǒng)見下圖,即客戶端通過 http 周期性地輪詢訪問 server 實(shí)現(xiàn)消息的即時通訊,也就是我們前面提到的 “信箱模型”?!靶畔淠P汀?雖然實(shí)現(xiàn)非常容易,但是消息的實(shí)時性不高。
我們在上一篇文章(單體架構(gòu) IM 系統(tǒng)之長輪詢方案設(shè)計(jì))中提出了優(yōu)化方案,即通過 http 長輪詢方式模擬出長連接的效果。
基于 http 長輪詢方式實(shí)現(xiàn)的 IM 系統(tǒng)的單體架構(gòu)中, server 節(jié)點(diǎn)還是無狀態(tài)化的嗎?所謂 “無狀態(tài)化” 節(jié)點(diǎn),是指進(jìn)程在內(nèi)存和硬盤中沒有獨(dú)立的數(shù)據(jù);很明顯,不同的 server 節(jié)點(diǎn)會 hold 住不同客戶端的 http 請求,也就是不同的 server 節(jié)點(diǎn)中會存儲不同客戶端的數(shù)據(jù), server 節(jié)點(diǎn)是有狀態(tài)化的;此時,點(diǎn)對點(diǎn)的消息發(fā)送邏輯肯定需要進(jìn)行調(diào)整。
大家可以先思考幾個問題:
-
在 http 長輪詢模式下, server 節(jié)點(diǎn)是有狀態(tài)的,如何實(shí)現(xiàn) server 節(jié)點(diǎn)的高可用呢?
-
客戶端 x 發(fā)消息給 y,如果 x 和 y 訪問的是不同的 server 節(jié)點(diǎn),應(yīng)該如何處理呢?
-
在 http 長輪詢模式下,怎樣判斷消息接收方是否在線呢?
我們直接給出在 http 長輪詢模式下,消息點(diǎn)對點(diǎn)的發(fā)送流程;以客戶端 x 發(fā)消息給客戶端 y 為例,如下:
-
客戶端 x 向 server 端發(fā)送 http 消息請求;
-
server 首先將消息直接落庫,分別寫 “云消息表” 和 “離線表”;
-
然后 server 訪問緩存,獲取消息接收方 y 的在線狀態(tài),若 y 不在線,則整個流程結(jié)束;
-
如果消息接收方 y 在線,通過訪問緩存獲取 y 連接的是哪一個 server 節(jié)點(diǎn);
-
如果 y 和 x 連接的同一個 server 節(jié)點(diǎn),則 server 將該消息通過 http 長輪詢返回給客戶端 y;
-
如果 y 連接的是另一個 server 節(jié)點(diǎn),此時需要當(dāng)前 server節(jié)點(diǎn)將消息推送到目標(biāo) server 節(jié)點(diǎn);
-
最后目標(biāo) server 節(jié)點(diǎn)將消息通過 http 長輪詢返回給客戶端 y。
在上述流程中,有兩個地方需要特別注意:
-
客戶端每一次發(fā)起 http 長輪詢請求,相當(dāng)于一次心跳,表示用戶的在線狀態(tài),需要在緩存中記錄客戶端的在線數(shù)據(jù);在 http 短輪詢模式中,緩存中記錄的 session 數(shù)據(jù)是 map<uid, {type, cmd, time}> ,在 http 長輪詢模式中,需要記錄客戶端請求的是哪一個 server 節(jié)點(diǎn),所以 session 類型為 map<uid, {type, cmd, time, serverip}>。
-
不管消息接收方在線與否,server 節(jié)點(diǎn)接收消息后,都需要寫 “離線表”,這樣設(shè)計(jì)的原因是為了提高消息的可靠性;因?yàn)榧词褂脩?“在線”,在 http 長輪詢返回時,客戶端有可能接收不到消息,同時,在一次完整的 http 長輪詢請求的間隙中,消息都是有丟失的可能的,所以持久化 “離線表” 是可靠性的保證;因此,在每一次 http 長輪詢請求中,都需要訪問 “離線表”,一是刪除客戶端已經(jīng)收到的消息,二是從 “離線表” 中獲取還未收到的消息。
在 http 長輪詢模式下, server 節(jié)點(diǎn)是有狀態(tài)的,那么其高可用如何保證呢?這個問題很容易解決:首先 server 節(jié)點(diǎn)肯定要集群化部署,然后由 反向代理 nginx 轉(zhuǎn)發(fā)請求到 server ; nginx 通過配置實(shí)現(xiàn)客戶端ip的會話保持,即將相同的客戶端請求始終轉(zhuǎn)發(fā)到固定的 server 節(jié)點(diǎn); 當(dāng) server 節(jié)點(diǎn)掛掉之后,nginx 將請求轉(zhuǎn)發(fā)到其他 server 節(jié)點(diǎn)即可,服務(wù)仍將持續(xù)提供,只需變更緩存中客戶端狀態(tài)信息即可。
單體架構(gòu) IM 系統(tǒng),從架構(gòu)到設(shè)計(jì),從協(xié)議到邏輯,其關(guān)鍵點(diǎn)都進(jìn)行了 一 一 分析;最后,我們簡單聊一下 server 的整體設(shè)計(jì),server 通過 Go語言進(jìn)行了實(shí)現(xiàn),見下圖。
-
主協(xié)程,不處理任何的業(yè)務(wù)邏輯,用于接收外部信號,如關(guān)閉程序等;
-
子協(xié)程,用于接收客戶端連接,針對每一個客戶端連接,子協(xié)程都會生成兩個協(xié)程來維護(hù)該連接,即:每一條連接會有一個獨(dú)立的協(xié)程組來維護(hù)(該協(xié)程組中有兩個協(xié)程,一個用于讀,一個用于寫);
-
連接管理器,實(shí)現(xiàn)對所有連接的管理,從連接中讀取請求交由業(yè)務(wù)邏輯模塊處理;
-
業(yè)務(wù)邏輯模塊,實(shí)現(xiàn)核心的業(yè)務(wù)邏輯,包括:登錄、登出、心跳、發(fā)消息等;
-
在線用戶管理器,維護(hù)連接當(dāng)前 server 節(jié)點(diǎn)所有的客戶端;如果消息接收方在當(dāng)前 server 節(jié)點(diǎn),在線用戶管理器通過 管道(chan)將消息傳輸給連接管理器中消息接收方的連接;
-
通訊協(xié)議,是公共協(xié)議定義,由【連接管理器】【業(yè)務(wù)邏輯模塊】【在線用戶管理器】共同引用。
關(guān)于 “每一條連接會有一個獨(dú)立的協(xié)程組來維護(hù)”,是 Go 語言通用的高效網(wǎng)絡(luò)編程模型,見下圖。
-
客戶端與服務(wù)端建立連接時,在服務(wù)端其實(shí)創(chuàng)建了一個 socket (即 fd 或句柄);
-
然后為該 socket 生成一個協(xié)作組,該協(xié)程組包括兩個協(xié)程: 協(xié)程1-1,負(fù)責(zé)對 socket 進(jìn)行讀; 協(xié)程1-2,負(fù)責(zé)對 socket 進(jìn)行寫;這兩個協(xié)程,一個讀一個寫互不影響,高效協(xié)作;
-
當(dāng)需要向客戶端寫消息時,不管是當(dāng)前socket 請求的數(shù)據(jù),還是從其他 socket 中讀取的數(shù)據(jù),必須通過協(xié)程組的管道(channel) 作為入口,然后協(xié)程1-2會從 channel 中讀取數(shù)據(jù)然后寫入到 socket 中。
最后,總結(jié)文中關(guān)鍵:
1、基于 http 長輪詢方式實(shí)現(xiàn)的 IM 系統(tǒng)的單體架構(gòu)中, server 節(jié)點(diǎn)是有狀態(tài)的;
2、基于 http 長輪詢發(fā)消息流程:消息到達(dá) serer 后,先落庫;若消息接收方在當(dāng)前 server 節(jié)點(diǎn),直接返回,否則需要將消息推送到目標(biāo) server 節(jié)點(diǎn);
3、 基于 http 長輪詢方式實(shí)現(xiàn)的 IM 系統(tǒng),緩存中需要記錄客戶端連接的是哪一個 server 節(jié)點(diǎn);
4、 在 http 長輪詢模式中,不管消息接收方在線與否,server 節(jié)點(diǎn)接收消息后,都需要寫 “離線表”;
5、 Go 語言通用的高效網(wǎng)絡(luò)編程模型:每一條連接會有一個獨(dú)立的協(xié)程組來維護(hù);協(xié)程1-1,負(fù)責(zé)對 socket 進(jìn)行讀; 協(xié)程1-2,負(fù)責(zé)對 socket 進(jìn)行寫。
至此,“單體架構(gòu)?IM 系統(tǒng)” 核心問題全部講完了,你是否還記得如下關(guān)鍵點(diǎn):
為什么要采用單體架構(gòu)?
單體架構(gòu)有怎樣的優(yōu)勢?
單體架構(gòu)的IM系統(tǒng)是怎樣的?
單體架構(gòu) IM 系統(tǒng)的消息收發(fā)邏輯是如何實(shí)現(xiàn)的?
什么是 “信箱模型” ,有什么優(yōu)勢和缺點(diǎn)?
“信箱模型” 消息的實(shí)時性如何提升?
http 長輪詢方式的兩種落地方案:“定時器” 和 “時間輪” 如何實(shí)現(xiàn)?
上述問題都可從以下四篇文章中找到答案:
《單體架構(gòu) IM 系統(tǒng)之架構(gòu)設(shè)計(jì)》
《單體架構(gòu) IM 系統(tǒng)之核心業(yè)務(wù)工作實(shí)現(xiàn)》
《單體架構(gòu) IM 系統(tǒng)之長輪詢方案設(shè)計(jì)》
《單體架構(gòu) IM 系統(tǒng)之 Server 節(jié)點(diǎn)狀態(tài)化分析》
分層架構(gòu)?IM 系統(tǒng)的關(guān)鍵問題,后續(xù)文章馬上更新跟進(jìn)......