直播系統(tǒng)聊天技術(shù)(八):vivo直播系統(tǒng)中IM消息模塊的架構(gòu)實踐

本文由vivo互聯(lián)網(wǎng)技術(shù)團(tuán)隊LinDu、Li Guolin分享,有較多修訂和改動。
1、引言
IM即時消息模塊是直播系統(tǒng)的重要組成部分,一個穩(wěn)定、有容錯、靈活的、支持高并發(fā)的消息模塊是影響直播系統(tǒng)用戶體驗的重要因素。
本文針對秀場直播,結(jié)合我們一年以來通過處理不同的業(yè)務(wù)線上問題,進(jìn)行了技術(shù)演進(jìn)式的IM消息模塊架構(gòu)的升級與調(diào)整,并據(jù)此進(jìn)行了技術(shù)總結(jié)、整理成文,希望借此機(jī)會分享給大家。

在目前大部分主流的直播系統(tǒng)中,推拉流是實現(xiàn)直播視頻業(yè)務(wù)最基本的技術(shù)點,IM實時消息技術(shù)則是實現(xiàn)觀看直播的所有用戶和主播實現(xiàn)互動的關(guān)鍵技術(shù)點。

通過直播系統(tǒng)中的IM消息模塊,我們可以完成公屏互動、彩色彈幕、全網(wǎng)送禮廣播、私信、PK等核心秀場直播的功能開發(fā)。“IM消息”作為用戶和用戶、用戶和主播之間“溝通”的信息橋梁,如何保證“信息橋梁”的在高并發(fā)場景下保持穩(wěn)定可靠,是直播系統(tǒng)演進(jìn)過程中一個重要的話題。
學(xué)習(xí)交流:
- 移動端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點此)
(本文同步發(fā)布于:http://www.52im.net/thread-3994-1-1.html)
2、系列文章
本文是系列文章中的第8篇:
《直播系統(tǒng)聊天技術(shù)(一):百萬在線的美拍直播彈幕系統(tǒng)的實時推送技術(shù)實踐之路》
《直播系統(tǒng)聊天技術(shù)(二):阿里電商IM消息平臺,在群聊、直播場景下的技術(shù)實踐》
《直播系統(tǒng)聊天技術(shù)(三):微信直播聊天室單房間1500萬在線的消息架構(gòu)演進(jìn)之路》
《直播系統(tǒng)聊天技術(shù)(四):百度直播的海量用戶實時消息系統(tǒng)架構(gòu)演進(jìn)實踐》
《直播系統(tǒng)聊天技術(shù)(五):微信小游戲直播在Android端的跨進(jìn)程渲染推流實踐》
《直播系統(tǒng)聊天技術(shù)(六):百萬人在線的直播間實時聊天消息分發(fā)技術(shù)實踐》
《直播系統(tǒng)聊天技術(shù)(七):直播間海量聊天消息的架構(gòu)設(shè)計難點實踐》
《直播系統(tǒng)聊天技術(shù)(八):vivo直播系統(tǒng)中IM消息模塊的架構(gòu)實踐》(* 本文)
3、直播消息的技術(shù)特征
在直播業(yè)務(wù)中,有幾個關(guān)于消息模型的核心概念,我們先簡單地總結(jié)一下,方便大家對直播相關(guān)的消息模型有一個整體上的理解。
3.1 實體關(guān)系
直播系統(tǒng)消息模塊對應(yīng)的實體就是主播和觀眾。
主播和觀眾:對于IM系統(tǒng)來說,都是普通用戶,都會有一個唯一用戶標(biāo)識(用戶ID),它也是IM分發(fā)到點對點消息的重要標(biāo)識。
主播和房間號:一個主播對應(yīng)一個房間號(RoomId),主播在開播之前,進(jìn)行身份信息驗證之后,就會綁定唯一的房間號,房間號是IM系統(tǒng)進(jìn)行直播間消息分發(fā)的重要標(biāo)識。
3.2 消息類型劃分
按照直播業(yè)務(wù)特性,IM消息劃分的方式有很多方式,例如:
1)按照接收方維度進(jìn)行劃分;
2)按照直播間消息業(yè)務(wù)類型進(jìn)行劃分;
3)按照消息的優(yōu)先級進(jìn)行劃分;
4)按照消息的存儲方式進(jìn)行劃分等等。
按照接收方維度,我們是這樣進(jìn)行劃分的:
1)點對點消息(單聊消息);
2)直播間消息(群聊消息);
3)廣播消息(系統(tǒng)消息)。
按照具體的業(yè)務(wù)場景,我們是這樣進(jìn)行劃分的:
1)禮物消息;
2)公屏消息;
3)PK消息;
4)業(yè)務(wù)通知類消息。
消息能夠?qū)崟r準(zhǔn)確地分發(fā)到對應(yīng)的群體或者單個用戶終端都是非常必要的。
當(dāng)然,好的IM消息模型也能夠賦能業(yè)務(wù)一些新的能力,例如:
1)統(tǒng)計每個直播間的實時在線人數(shù);
2)捕獲用戶進(jìn)出直播間的事件;
3)統(tǒng)計每個用戶實時進(jìn)入直播間的時間。
3.3 消息優(yōu)先級
直播系統(tǒng)中的IM消息是有優(yōu)先級的,這一點是很重要的,與微信、QQ等標(biāo)準(zhǔn)社交聊天IM產(chǎn)品不一樣的地方是:直播間消息是分優(yōu)先級的。
微信等標(biāo)準(zhǔn)社交IM產(chǎn)品,不管是私聊還是群聊,每個人發(fā)送消息的優(yōu)先級基本上是一樣的,不存在誰的消息優(yōu)先級高,誰的消息優(yōu)先級低,都需要將消息準(zhǔn)確實時地分發(fā)到各個業(yè)務(wù)終端.但是直播因為業(yè)務(wù)場景的不同,消息分發(fā)的優(yōu)先級也是不一樣的。
舉例來說:如果一個直播間每秒只能渲染15~20個消息,一個熱點直播間一秒鐘產(chǎn)生的消息量大于20條或者更多,如果不做消息優(yōu)先級的控制,直接實時分發(fā)消息,那么導(dǎo)致的結(jié)果就是直播間公屏客戶端渲染卡頓,禮物彈框渲染過快,用戶觀看體驗大幅下降。所以我們要針對不同業(yè)務(wù)類型的消息,給出不同的消息優(yōu)先級。
再又比如:禮物消息大于公屏消息,同等業(yè)務(wù)類型的消息,大額禮物的消息優(yōu)先級又大于小額禮物的消息,高等級用戶的公屏消息優(yōu)先級高于低等級用戶或者匿名用戶的公屏消息,在做業(yè)務(wù)消息分發(fā)的時候,需要根據(jù)實際的消息優(yōu)先級,選擇性地進(jìn)行消息準(zhǔn)確地分發(fā)。
4、直播系統(tǒng)的消息模塊架構(gòu)模型
消息模塊架構(gòu)模型如下圖所示:

如上圖所示,我們消息模塊中消息的交互方式就是推拉結(jié)合。下面將分別詳細(xì)展開介紹用于“拉”的短輪詢和用于“推”的長連接技術(shù)。
5、短輪詢技術(shù)
正如上節(jié)中架構(gòu)圖所示,我們的架構(gòu)中使用上短輪詢技術(shù)。本節(jié)將詳細(xì)介紹之。(關(guān)于短輪詢技術(shù)的原理,可以看看這篇《網(wǎng)頁端IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket》)
5.1 短輪詢的業(yè)務(wù)模型
首先,我們先簡單描述一下短輪詢的時序邏輯和設(shè)計思想:
1)客戶端每隔2s輪詢服務(wù)器接口,參數(shù)是roomId和timestamp(timestamp第一次傳遞0或者null);
2)服務(wù)器根據(jù)roomId和timestamp查詢該房間在timestamp時間戳后產(chǎn)生的消息事件,返回限定條數(shù)的消息例如(例如返回10~15條,當(dāng)然在這個timestamp之后產(chǎn)生的消息數(shù)遠(yuǎn)遠(yuǎn)大于15條,不過因為客戶端渲染能力有限和過多的消息展示,會影響用戶體驗,所以限制返回的條數(shù)),并且同時返回這些消息中最后一條消息產(chǎn)生的時間戳timestamp,作為客戶端下次請求服務(wù)器的基準(zhǔn)請求時間戳;
3)以此反復(fù),這樣就可以每隔2s按照各個終端要求,更新每個直播間的最新消息了。

整體的技術(shù)邏輯如上圖所示,不過具體的時序可以再做精細(xì)化處理,后續(xù)再做具體的說明和細(xì)節(jié)說明。
5.2 短輪詢的存儲模型
短輪詢的消息存儲與正常的長連接的消息存儲有一定的區(qū)別,因為它不存在消息擴(kuò)散的問題。
我們需要做的消息存儲需要達(dá)到如下的業(yè)務(wù)目標(biāo):
1)消息插入時間復(fù)雜度要相對比較低;
2)消息查詢的復(fù)雜度要相對比較低;
3)消息的存儲的結(jié)構(gòu)體要相對比較小,不能占用太大的內(nèi)存空間或者磁盤空間;
4)歷史消息能夠按照業(yè)務(wù)需要做磁盤持久化存儲。
結(jié)合上述4點的技術(shù)要求,經(jīng)過小組成員的討論,我們決定使用Redis的SortedSet數(shù)據(jù)結(jié)構(gòu)進(jìn)行存儲。
具體實現(xiàn)思路:按照直播間產(chǎn)品業(yè)務(wù)類型,將業(yè)務(wù)消息劃分為如下四大類型:禮物、公屏、PK、通知。
一個直播間的消息使用四個Redis的SortedSet數(shù)據(jù)結(jié)構(gòu)進(jìn)行存儲。
SortedSet的key分別是:
1)"live::roomId::gift";
2)"live::roomId::chat";
3)"live::roomId::notify";
4)"live::roomId::pk"。
score分別是消息真實產(chǎn)生的時間戳,value就是序列化好的json字符串。
如下圖所示:

客戶端輪詢的時候,服務(wù)端查詢的邏輯如下所示:

?
很多同學(xué)會疑問,為什么不適用Redis的list的數(shù)據(jù)結(jié)構(gòu)呢?如下圖會進(jìn)行詳細(xì)的說明:

最后:我們再對比一下Redis的SortedSet和Redis的List這兩個數(shù)據(jù)結(jié)構(gòu)在直播消息存儲的時候,時間復(fù)雜度的相關(guān)分析(如下所示)。

以上:就是我們使用Redis的SortedSet數(shù)據(jù)結(jié)構(gòu)進(jìn)行消息存儲的一些簡單的設(shè)計思考,后續(xù)我們也會提到端輪詢的編碼時候,需要的注意點。
5.3 短輪詢的時間控制
短輪詢的時間控制及其重要,我們需要在直播觀眾觀看體驗QoE和服務(wù)器壓力之間找到一個很好的平衡點。
輪詢的間隔時間長:用戶體驗就會下降很多,直播觀看體驗就會變差,會有"一頓一頓"的感覺。
短輪詢的頻率過高:會導(dǎo)致服務(wù)器的壓力過大,也會出現(xiàn)很多次"空輪詢",所謂的"空輪詢"就是無效輪詢,也就是在上一秒有效輪詢返回有效消息之后,間隔期直播間沒有產(chǎn)生新的消息,就會出現(xiàn)無效的輪詢。
vivo直播目前每日的輪詢次數(shù)是10+億次,晚觀看直播高峰期的時候,服務(wù)器和Redis的CPU負(fù)載都會上升,dubbo的服務(wù)提供方的線程池一直處于高水位線上。這塊需要根據(jù)機(jī)器的和Redis的實時負(fù)載的壓力,做服務(wù)器的水平擴(kuò)容和Redis Cluster的節(jié)點擴(kuò)容,甚至讓一些超高熱度值的直播間負(fù)載到指定的Redis Cluster集群上,做到物理隔離,享受到“VIP”服務(wù),確保各個直播間的消息相互不影響。
直播人數(shù)不一樣的直播間,輪詢的時間也是可以配置的:
1)例如人數(shù)比較少的直播,百人以下的直播間,可以設(shè)置比較高頻的輪詢頻率(比如1.5s左右);
2)超過300人以上的,1000人以下可以2s左右;
3)萬人直播間可以設(shè)置2.5s左右。
這些配置應(yīng)該都可以通過配置中心實時下發(fā),客戶端能夠?qū)崟r更新輪詢的時間,調(diào)整的頻率可以根據(jù)實際直播間用戶體驗的效果,并且結(jié)合服務(wù)器的負(fù)載,找到一個輪詢間隔的相對最佳值。

5.4 短輪詢的注意點
1)服務(wù)端需要校驗客戶端傳遞過來的時間戳:
這一點非常重要,試想一下,如果觀眾在觀看直播的時候,將直播退出后臺,客戶端輪詢進(jìn)程暫停,當(dāng)用戶恢復(fù)直播觀看畫面進(jìn)程的時候,客戶端傳遞過來的時間就會是非常老舊甚至過期的時間,這個時間會導(dǎo)致服務(wù)器查詢Redis時出現(xiàn)慢查。
如果出現(xiàn)大量的服務(wù)器慢查的話,會導(dǎo)致服務(wù)器連接Redis的連接無法快速釋放,也會拖慢整個服務(wù)器的性能,會出現(xiàn)一瞬間大量的輪詢接口超時,服務(wù)質(zhì)量和QoE會下降很多。
2)客戶端需要校驗重復(fù)消息:
在極端情況下,客戶端有可能收到重復(fù)的消息,產(chǎn)生的原因可能如下,在某一個時刻客戶端發(fā)出roomId=888888×tamp=t1的請求,因為網(wǎng)絡(luò)不穩(wěn)定或者服務(wù)器GC的原因,導(dǎo)致該請求處理比較慢,耗時超過2s,但是因為輪詢時間到了,客戶端又發(fā)出了roomId=888888×tamp=t1的請求,服務(wù)器返回相同的數(shù)據(jù),就會出現(xiàn)客戶端重復(fù)渲染相同的消息進(jìn)行展示。
這樣也會影響用戶體驗,所以每一個客戶端有必要對重復(fù)消息進(jìn)行校驗。
3)海量數(shù)據(jù)無法實時返回渲染的問題:
設(shè)想一下,如果一個熱度極大的直播間,每秒鐘產(chǎn)生的消息量是數(shù)千或者上萬的時候,按照上面的存儲和查詢思路是有漏洞的。
因為我們每次因為各個因素的限制,每次只返回10~20條消息,那么我們需要很長的時間才能把這熱度很多的一秒鐘的數(shù)據(jù)全部返回,這樣就會造成最新的消息無法快速優(yōu)先返回。
所以輪詢返回的消息也可以按照消息優(yōu)先級進(jìn)行選擇性丟棄。
5.5 短輪詢的優(yōu)缺點
客戶端輪詢服務(wù)服務(wù)器查詢直播間的消息的好處是顯而易見的,消息的分發(fā)是非常實時和準(zhǔn)確的,很難出現(xiàn)因為網(wǎng)絡(luò)顫抖導(dǎo)致消息無法到達(dá)的場景。
不過壞處也是非常明顯的,服務(wù)器在業(yè)務(wù)高峰期的負(fù)載壓力很大,如果直播間的所有消息都是通過輪詢分發(fā),長期以往,服務(wù)器是很難通過水平擴(kuò)容的方式來達(dá)到線性增長的。
6、長連接技術(shù)
6.1 長連接的架構(gòu)?

?
如上圖所示,整體直播長連接的流程如下:
1)手機(jī)客戶端首先通過http請求長連接服務(wù)器,獲取TCP長連接的IP地址,長連接服務(wù)器根據(jù)路由和負(fù)載策略,返回最優(yōu)的可連接的IP列表;
2)手機(jī)客戶端根據(jù)長連接服務(wù)器返回的IP列表,進(jìn)行長連接的客戶端的連接請求接入,長連接服務(wù)器收到連接請求,進(jìn)而建立連接;
3)手機(jī)客戶端發(fā)送鑒權(quán)信息,進(jìn)行通信信息的鑒權(quán)和身份信息確認(rèn),最后長連接建立完成,長連服務(wù)器需要對連接進(jìn)行管理,心跳監(jiān)測,斷線重連等操作。
長連接服務(wù)器集群的基本架構(gòu)圖:

?
如上圖所示,集群按照地域進(jìn)行業(yè)務(wù)劃分,不同地域的終端機(jī)器按需接入。
6.2 長連接建立和管理
為了使消息即時、高效、安全地觸達(dá)用戶,直播客戶端和IM系統(tǒng)建立了一條加密的全雙工數(shù)據(jù)通路,收發(fā)消息均使用該通道,當(dāng)大量用戶在線的時候,維護(hù)這些連接、保持會話,需要用到大量內(nèi)存和CPU資源。

?
IM接入層盡量保持功能簡潔:業(yè)務(wù)邏輯下沉到后面邏輯服務(wù)中進(jìn)行處理,為了防止發(fā)布的時候,重啟進(jìn)程會導(dǎo)致大量的外網(wǎng)設(shè)備重新建立連接,影響用戶體驗。
接入層提供熱更新的發(fā)布方案:連接維護(hù)、賬號管理等不經(jīng)常改動的基礎(chǔ)邏輯放入主程序中,業(yè)務(wù)邏輯采用so插件的方式嵌入到程序的,修改業(yè)務(wù)邏輯時只需要重新加載一次插件即可,可以保證與設(shè)備的長連接不受影響。
6.3 長連接保活
長連接建立后,如果中間網(wǎng)絡(luò)斷開,服務(wù)端和客戶端都無法感知,造成假在線的情況。
因此維護(hù)好這個“長連接”的一個關(guān)鍵的問題在于能夠讓這個“長連接”能夠在中間鏈路出現(xiàn)問題時,讓連接的兩端能夠快速得到通知,然后通過重連來建立新的可用連接,從而讓我們這個長連接一直保持高可用狀態(tài)。
我們的作法是:讓IM消息模塊在服務(wù)端開啟TCP的keeplive?;钐綔y機(jī)制,并在客戶端啟用智能心跳。

利用TCP的keeplive?;钐綔y功能,可以探知客戶端崩潰、中間網(wǎng)絡(luò)端開和中間設(shè)備因超時刪除連接相關(guān)的連接表等意外情況,從而保證在意外發(fā)生時,服務(wù)端可以釋放半打開的TCP連接。
客戶端啟動智能心跳不僅能在消耗極少的電和網(wǎng)絡(luò)流量條件下,通知服務(wù)器客戶端存活狀態(tài)、定時的刷新NAT內(nèi)外網(wǎng)IP映射表,還能在網(wǎng)絡(luò)變更時自動重連長連接。
Jack Jiang注:實際上,移動網(wǎng)絡(luò)下,TCP協(xié)議自身的keeplive機(jī)制用處并不大,有興趣可以詳讀這兩篇:《為什么說基于TCP的移動端IM仍然需要心跳?;睿俊?、《徹底搞懂TCP協(xié)議層的KeepAlive保活機(jī)制》。
有關(guān)長連接心跳機(jī)制的更詳細(xì)資料,可以參閱:
《手把手教你用Netty實現(xiàn)網(wǎng)絡(luò)通信程序的心跳機(jī)制、斷線重連機(jī)制》
《一文讀懂即時通訊應(yīng)用中的網(wǎng)絡(luò)心跳包機(jī)制:作用、原理、實現(xiàn)思路等》
《移動端IM實踐:實現(xiàn)Android版微信的智能心跳機(jī)制》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
《一種Android端IM智能心跳算法的設(shè)計與實現(xiàn)探討(含樣例代碼)》
《正確理解IM長連接、心跳及重連機(jī)制,并動手實現(xiàn)》
《萬字長文:手把手教你實現(xiàn)一套高效的IM長連接自適應(yīng)心跳?;顧C(jī)制》
《Web端即時通訊實踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?》
7、直播間IM消息的實時分發(fā)
7.1 概述
IM長連接分發(fā)消息的整體流程圖:

在整合客戶端、IM長連接服務(wù)器模塊和直播業(yè)務(wù)服務(wù)器模塊這三個模塊的時候,整體消息的分發(fā)邏輯遵循幾個基本原則。
基本原則如下:
1)單聊、群聊、廣播消息所有的消息都是由直播業(yè)務(wù)服務(wù)器調(diào)用IM長連接服務(wù)器的接口,將需要分發(fā)的消息分發(fā)到各個業(yè)務(wù)直播間;
2)業(yè)務(wù)服務(wù)器對直播間產(chǎn)生的事件進(jìn)行對應(yīng)的業(yè)務(wù)類型做響應(yīng)的處理,例如送禮扣減虛擬貨幣,發(fā)送公屏進(jìn)行文本健康校驗等;
3)客戶端接受直播業(yè)務(wù)服務(wù)器的信令控制,消息是通過長連接通道分發(fā)還是http短輪詢分發(fā),都是由直播業(yè)務(wù)服務(wù)器控制,客戶端屏蔽底層消息獲取的方式細(xì)節(jié),客戶端上層接受統(tǒng)一的消息數(shù)據(jù)格式,進(jìn)行對應(yīng)的業(yè)務(wù)類型消息處理渲染。
7.2 直播間成員管理和消息分發(fā)
直播間成員是直播間最重要的基礎(chǔ)元數(shù)據(jù),單個直播間的用戶量實際上是無上限的,且呈現(xiàn)大直播若干個(大于30W同時在線)、中直播間幾百個、小直播幾萬個這樣分布。如何管理直播間成員是一個直播間系統(tǒng)架構(gòu)中核心功能之一。
常見的管理方式有如下兩種:
1)為直播間分配固定分片:
用戶與具體的分片存在映射關(guān)系,每個分片中保存用戶相對隨機(jī)。

?
采用固定分片的方式算法實現(xiàn)簡單,但是對于用戶少的直播間有可能分片承載的用戶數(shù)量少,對于用戶大的直播間有可能分片承載用戶量又比較大,固定分片存在天然伸縮性差的特點。
2)動態(tài)分片:
規(guī)定分片用戶數(shù),當(dāng)用戶數(shù)超過閾值時,增加一個新的分片,分片數(shù)量可以隨著用戶數(shù)增加而變化。

?
動態(tài)分片可以根據(jù)直播間人數(shù)自動生成分片,滿了就開辟新片,盡量使每個分片的用戶數(shù)達(dá)到閾值,但已有分片的用戶數(shù)量隨著用戶進(jìn)出直播間變化,維護(hù)復(fù)雜度比較高。
7.3 直播間消息分發(fā)
直播間中有進(jìn)出場消息、文本消息、禮物消息和公屏消息等多種多樣消息。消息的重要程度不一樣,可為每個消息設(shè)定相應(yīng)的優(yōu)先級。
不同優(yōu)先級的消息放在不同的消息隊列中,高優(yōu)先級的消息優(yōu)先發(fā)送給客戶端,消息堆積超過限制時,丟棄最早、低優(yōu)先級的消息。
另外:直播間消息屬于實時性消息,用戶獲取歷史消息、離線消息的意義不大,消息采用讀擴(kuò)散的方式存儲組織。
直播間消息發(fā)送時:根據(jù)直播間成員分片通知對應(yīng)的消息發(fā)送服務(wù),再把消息分別下發(fā)給分片中對應(yīng)的每一個用戶。為了實時、高效地把直播間消息下發(fā)給用戶,當(dāng)用戶有多條未接收消息時,下發(fā)服務(wù)采用批量下發(fā)的方式將多條消息發(fā)送給用戶。

?
7.4 長連接的消息壓縮
在使用TCP長連接分發(fā)直播間消息的時候,也需要注意消息體的大小。
如果某一個時刻,分發(fā)消息的數(shù)量比較大,或者同一個消息在做群播場景的時候,群播的用戶比較多,IM連接層的機(jī)房的出口帶寬就會成為消息分發(fā)的瓶頸。
所以如何有效的控制每一個消息的大小、壓縮每一個消息的大小,是我們也需要思考的問題。
我們目前通過兩種方式來做相關(guān)消息體結(jié)構(gòu)的優(yōu)化:
1)使用protobuf協(xié)議數(shù)據(jù)交換格式;
2)相同類型的消息進(jìn)行合并發(fā)送。
經(jīng)過我們線上測試,使用protobuf數(shù)據(jù)交換格式,平均每一個消息節(jié)省43%的字節(jié)大小,可以大大幫助我們節(jié)省機(jī)房出口帶寬。(關(guān)于protubuf的更多資料,請閱讀《Protobuf通信協(xié)議詳解:代碼演示、詳細(xì)原理介紹等》、《強(qiáng)列建議將Protobuf作為你的即時通訊應(yīng)用數(shù)據(jù)傳輸格式》)
7.5 塊消息
所謂塊消息,也是我們借鑒其他直播平臺的技術(shù)方案,也就是多個消息進(jìn)行合并發(fā)送。
直播業(yè)務(wù)服務(wù)器不是產(chǎn)生一個消息就立馬調(diào)用IM長連接服務(wù)器集群直接進(jìn)行消息的分發(fā)。
主要思想:就是以直播間為維度,每隔1s或者2s,以勻速的時間間隔將在這個時間段業(yè)務(wù)系統(tǒng)產(chǎn)生的消息進(jìn)行分發(fā)。
每秒分發(fā)10~20個消息,如果每秒中,業(yè)務(wù)服務(wù)器積累到的消息大于10~20個,那就按照消息的優(yōu)先級進(jìn)行丟棄。如果這10~20個消息的優(yōu)先級都比較高,例如都是禮物類型的消息,則將消息放在后一個消息塊進(jìn)行發(fā)送。
這樣做的好處如下:
1)減少傳輸消息頭:合并消息,可以減少傳輸多余的消息頭,多個消息一起發(fā)送,在自定義的TCP傳輸協(xié)議中,可以共用消息頭,進(jìn)一步減少消息字節(jié)數(shù)大?。?/p>
2)防止消息風(fēng)暴:直播業(yè)務(wù)服務(wù)器可以很方便的控制消息分發(fā)的速度,不會無限制的分發(fā)消息到直播客戶端,客戶端無法處理如此多的消息;
3)提升用戶體驗:直播間的消息因為流速正常,渲染的節(jié)奏比較均勻,會帶來很好的用戶直播體驗,整個直播效果會很流暢。

8、消息丟棄策略
不管是http短輪詢還是長連接,在高熱度值直播間出現(xiàn)的時候,都會存在消息丟棄的情況。
例如:在游戲直播中,有出現(xiàn)比較精彩瞬間的時候,評論公屏數(shù)會瞬間增加,同時送低價值的禮物的消息也會瞬間增加很多,用來表示對自己選手精彩操作的支持,那么服務(wù)器通過IM長連接或者h(yuǎn)ttp短輪詢每秒分發(fā)的消息數(shù)就會數(shù)千或者上萬。
一瞬間的消息突增,會導(dǎo)致客戶端出現(xiàn)如下幾個問題:
1)客戶端通過長連接獲取的消息突增,下行帶寬壓力突增,其他業(yè)務(wù)可能會受到影響(例如禮物的svga無法及時下載播放);
2)客戶端無法快速處理渲染如此多的禮物和公屏消息,CPU壓力突增,音視頻處理也會受到影響;
3)因消息存在積壓,導(dǎo)致會展示過期已久消息的可能,用戶體驗(QoE)指標(biāo)會下降。
所以:因為這些原因,消息是存在丟棄的必要的。
舉一個簡單的例子:禮物的優(yōu)先級一定是高于公屏消息的,PK進(jìn)度條的消息一定是高于全網(wǎng)廣播類消息的,高價值禮物的消息又高于低價值禮物的消息。
根據(jù)這些業(yè)務(wù)理論,我們在開發(fā)實踐中,可以做如下的控制:
1)選擇性丟棄低優(yōu)先級消息:結(jié)合具體業(yè)務(wù)特點,給各個業(yè)務(wù)類型的消息劃分出不同等級,在消息分發(fā)觸發(fā)流控的時候,根據(jù)消息優(yōu)先級選擇性丟棄低優(yōu)先級消息;
2)選擇性丟棄“老”消息:消息結(jié)構(gòu)體新增創(chuàng)建時間和發(fā)送時間兩個字段,在實際調(diào)用長連接通道的時候,需要判斷當(dāng)前時間與消息的創(chuàng)建時間是夠間隔過大,如果過大,則直接丟棄消息;
3)增益消息(糾正消息):在業(yè)務(wù)開發(fā)中,消息的設(shè)計中,盡量地去設(shè)計增益消息,增益消息指的是后續(xù)到達(dá)的消息能夠包含前續(xù)到達(dá)的消息。
針對上述第?3)?條:舉例來說,9點10的消息,主播A和主播B的PK值是20比10,那么9點11分分發(fā)的PK消息值就是22比10,而不能分發(fā)增量消息2:0,希望客戶端做PK條的累加(20+2 :10+0)。但是存在消息因為網(wǎng)絡(luò)顫抖或者前置消息丟棄,導(dǎo)致消息丟棄,所以分發(fā)增益消息或者糾正消息會能夠幫助業(yè)務(wù)重新恢復(fù)正常。
9、寫在最后
任何一個直播系統(tǒng),隨著業(yè)務(wù)的發(fā)展和直播間人氣不斷的增加,消息系統(tǒng)遇到的問題和挑戰(zhàn)也會隨之而來。不管是長連接的消息風(fēng)暴,還是海量http短輪詢的請求,都會導(dǎo)致服務(wù)器壓力的劇增,都是我們需要不斷解決和優(yōu)化的。
我們要針對每一個時期的業(yè)務(wù)特點,做直播消息的持續(xù)升級,做可演進(jìn)的IM消息模塊,確保消息分發(fā)的能力能夠確保業(yè)務(wù)的持續(xù)發(fā)展。
vivo直播消息模塊也是逐步演進(jìn)的,演進(jìn)的動力主要來自于因為業(yè)務(wù)的發(fā)展,隨著業(yè)務(wù)形態(tài)的多樣化,觀看的用戶數(shù)越來越多,系統(tǒng)的功能也會逐步增多,也會遇到各種性能瓶頸,為了解決實際遇到的性能問題,會逐一進(jìn)行代碼分析,接口性能瓶頸的分析,然后給出對應(yīng)的解決方案或者解耦方案,消息模塊也不例外。
希望這篇文章能夠給大家?guī)碇辈ハ到y(tǒng)中IM消息模塊的設(shè)計啟發(fā)。
10、參考資料
[1]?徹底搞懂TCP協(xié)議層的KeepAlive?;顧C(jī)制
[2]?拔掉網(wǎng)線再插上,TCP連接還在嗎?一文即懂!
[3]?Protobuf通信協(xié)議詳解:代碼演示、詳細(xì)原理介紹等
[4]?還在用JSON? Protobuf讓數(shù)據(jù)傳輸更省更快(原理篇)
[5]?為何基于TCP協(xié)議的移動端IM仍然需要心跳保活機(jī)制?
[6]?移動端IM實踐:實現(xiàn)Android版微信的智能心跳機(jī)制
[7]?手把手教你實現(xiàn)一套高效的IM長連接自適應(yīng)心跳?;顧C(jī)制
[8]?Web端即時通訊技術(shù)盤點:短輪詢、Comet、Websocket、SSE
[9]?網(wǎng)頁端IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket
[10]?微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解
(本文同步發(fā)布于:http://www.52im.net/thread-3994-1-1.html)
直播系統(tǒng)聊天技術(shù)(八):vivo直播系統(tǒng)中IM消息模塊的架構(gòu)實踐的評論 (共 條)
