詳解玩轉(zhuǎn)直播系列之消息模塊演進(jìn)
一、背景
即時(shí)消息(IM)系統(tǒng)是直播系統(tǒng)重要的組成部分,一個(gè)穩(wěn)定的,有容錯(cuò)的,靈活的,支持高并發(fā)的消息模塊是影響直播系統(tǒng)用戶體驗(yàn)的重要因素。IM長(zhǎng)連接服務(wù)在直播系統(tǒng)有發(fā)揮著舉足輕重的作用。
在目前大部分主流的直播業(yè)務(wù)中,推拉流是實(shí)現(xiàn)直播業(yè)務(wù)最基本的技術(shù)點(diǎn),消息技術(shù)則是實(shí)現(xiàn)觀看直播的所有用戶和主播實(shí)現(xiàn)互動(dòng)的關(guān)鍵技術(shù)點(diǎn),通過直播IM系統(tǒng)模塊,我們可以完成公屏互動(dòng),彩色彈幕,全網(wǎng)送禮廣播,私信,PK等核心秀場(chǎng)直播的功能開發(fā)。"IM消息"作為用戶和用戶,用戶和主播之間"溝通"的信息橋梁,如何保證"信息橋梁"的在高并發(fā)場(chǎng)景下保持穩(wěn)定可靠,是直播系統(tǒng)演進(jìn)過程中一個(gè)重要的話題。
二、直播消息業(yè)務(wù)
在直播業(yè)務(wù)中,有幾個(gè)核心的關(guān)于消息模型的概念,我們先簡(jiǎn)單地介紹一下,方便大家對(duì)直播相關(guān)的消息模型有一個(gè)整體上的理解。
2.1、主播與用戶
主播和觀眾,對(duì)于IM系統(tǒng)來說,都是一個(gè)普通用戶,都會(huì)有一個(gè)唯一用戶標(biāo)識(shí),也是IM分發(fā)到點(diǎn)對(duì)點(diǎn)消息的重要標(biāo)識(shí)。
2.2、房間號(hào)
一個(gè)主播對(duì)應(yīng)一個(gè)房間號(hào)(RoomId),主播在開播之前,進(jìn)行身份信息驗(yàn)證之后,就會(huì)綁定唯一的房間號(hào),房間號(hào)是IM系統(tǒng)進(jìn)行直播間消息分發(fā)的重要標(biāo)識(shí)。
2.3、消息類型劃分
按照直播業(yè)務(wù)特性,IM消息劃分的方式有很多方式,例如按照接收方維度進(jìn)行劃分,按照直播間消息業(yè)務(wù)類型進(jìn)行劃分,按照消息的優(yōu)先級(jí),存儲(chǔ)方式都可以進(jìn)行不同的劃分等等方式。
通常,我們按照接收方維度進(jìn)行劃分有如下幾個(gè)類型的消息:
- 點(diǎn)對(duì)點(diǎn)消息(單播消息)
- 直播間消息(群播消息)
- 廣播消息
按照具體的業(yè)務(wù)場(chǎng)景有如下幾個(gè)類型的消息:
- 禮物消息
- 公屏消息
- PK消息
- 業(yè)務(wù)通知類消息
消息能夠?qū)崟r(shí)準(zhǔn)確地分發(fā)到對(duì)應(yīng)的群體或者單個(gè)用戶終端都是非常必要的。當(dāng)然好一點(diǎn)的IM消息模型也能夠賦能業(yè)務(wù)一些新的能力,例如如下的能力:
統(tǒng)計(jì)每個(gè)直播間的實(shí)時(shí)在線人數(shù)
捕獲用戶進(jìn)出直播間的事件
統(tǒng)計(jì)每個(gè)用戶實(shí)時(shí)進(jìn)入直播間的時(shí)間
2.4、消息優(yōu)先級(jí)
直播的消息是有優(yōu)先級(jí)的,這一點(diǎn)是很重要的,與微信,QQ等聊天IM產(chǎn)品不一樣的地方是直播間消息是分優(yōu)先級(jí)的。
微信等聊天消息產(chǎn)品,不管是私聊還是群聊,每個(gè)人發(fā)送消息的優(yōu)先級(jí)基本上是一樣的,不存在誰的消息優(yōu)先級(jí)高,誰的消息優(yōu)先級(jí)低,都需要將消息準(zhǔn)確實(shí)時(shí)地分發(fā)到各個(gè)業(yè)務(wù)終端,但是直播因?yàn)闃I(yè)務(wù)場(chǎng)景的不同,消息分發(fā)的優(yōu)先級(jí)也是不一樣的。
舉例來說,如果一個(gè)直播間每秒只能渲染15~20個(gè)消息,如果一個(gè)熱點(diǎn)直播間一秒鐘產(chǎn)生的消息量大于20條或者更多,如果不做消息優(yōu)先級(jí)的控制,直接實(shí)時(shí)分發(fā)消息,那么導(dǎo)致的結(jié)果就是直播間公屏客戶端渲染卡頓,禮物彈框渲染過快,用戶觀看體驗(yàn)大幅下降,所以我們要針對(duì)不同業(yè)務(wù)類型的消息,給出不同的消息優(yōu)先級(jí)。
舉例來說,禮物消息大于公屏消息,同等業(yè)務(wù)類型的消息,大額禮物的消息優(yōu)先級(jí)又大于小額禮物的消息,高等級(jí)用戶的公屏消息優(yōu)先級(jí)高于低等級(jí)用戶或者匿名用戶的公屏消息,在做業(yè)務(wù)消息分發(fā)的時(shí)候,需要根據(jù)實(shí)際的消息優(yōu)先級(jí),選擇性地進(jìn)行消息準(zhǔn)確地分發(fā)。
三、消息技術(shù)點(diǎn)
3.1、消息架構(gòu)模型
3.2、短輪詢 VS 長(zhǎng)鏈接
3.2.1、短輪詢
短輪詢的業(yè)務(wù)模型
首先我們先簡(jiǎn)單地描述一下短輪詢時(shí)間的過程和基本設(shè)計(jì)思想:
客戶端每隔2s輪詢服務(wù)器接口,參數(shù)是roomId和timestamp,timestamp第一次傳遞0或者null。
服務(wù)器根據(jù)roomId和timestamp查詢?cè)摲块g在timestamp時(shí)間戳后產(chǎn)生的消息事件,返回限定條數(shù)的消息例如(例如返回10~15條,當(dāng)然在這個(gè)timestamp之后產(chǎn)生的消息數(shù)遠(yuǎn)遠(yuǎn)大于15條,不過因?yàn)榭蛻舳虽秩灸芰τ邢藓瓦^多的消息展示,會(huì)影響用戶體驗(yàn),所以限制返回的條數(shù)),并且同時(shí)返回這些消息中最后一條消息產(chǎn)生的時(shí)間戳timestamp,作為客戶端下次請(qǐng)求服務(wù)器的基準(zhǔn)請(qǐng)求時(shí)間戳。
以此反復(fù),這樣就可以每隔2s按照各個(gè)終端要求,更新每個(gè)直播間的最新消息了
整體的主體思想如上圖所示,不過具體的時(shí)間可以再做精細(xì)化處理,后續(xù)再做具體的說明和細(xì)節(jié)說明。
短輪詢的存儲(chǔ)模型
短輪詢的消息存儲(chǔ)與正常的長(zhǎng)連接的消息存儲(chǔ)有一定的區(qū)別,不存在消息擴(kuò)散的問題,我們需要做的消息存儲(chǔ)需要達(dá)到如下的業(yè)務(wù)目標(biāo):
消息插入時(shí)間復(fù)雜度要相對(duì)比較低;
消息查詢的復(fù)雜度要相對(duì)比較低;
消息的存儲(chǔ)的結(jié)構(gòu)體要相對(duì)比較小,不能占用太大的內(nèi)存空間或者磁盤空間;
歷史消息能夠按照業(yè)務(wù)需要做磁盤持久化存儲(chǔ);
結(jié)合上述4點(diǎn)的技術(shù)要求,畢竟經(jīng)過小組成員的討論,我們決定使用Redis的SortedSet數(shù)據(jù)結(jié)構(gòu)進(jìn)行存儲(chǔ),具體實(shí)現(xiàn)思路:按照直播間產(chǎn)品業(yè)務(wù)類型,將業(yè)務(wù)消息劃分為如下四大類型:禮物,公屏,PK,通知。
一個(gè)直播間的消息使用四個(gè)Redis的SortedSet數(shù)據(jù)結(jié)構(gòu)進(jìn)行存儲(chǔ),SortedSet的key分別是"live::roomId::gift","live::roomId::chat","live::roomId::notify","live::roomId::pk",score分別是消息真實(shí)產(chǎn)生的時(shí)間戳,value就是序列化好的json字符串,如下圖所示:
客戶端輪詢的時(shí)候,服務(wù)端查詢的邏輯如下所示:
很多同學(xué)會(huì)疑問,為什么不適用Redis的list的數(shù)據(jù)結(jié)構(gòu)呢?如下圖會(huì)進(jìn)行詳細(xì)的說明:
最后我們?cè)賹?duì)比一下Redis的SortedSet和Redis的List這兩個(gè)數(shù)據(jù)結(jié)構(gòu)在直播消息存儲(chǔ)的時(shí)候,時(shí)間復(fù)雜度的相關(guān)分析。
以上,就是我們使用Redis的SortedSet數(shù)據(jù)結(jié)構(gòu)進(jìn)行消息存儲(chǔ)的一些簡(jiǎn)單的設(shè)計(jì)思考,后續(xù)我們也會(huì)提到端輪詢的編碼時(shí)候,需要的注意點(diǎn)。
短輪詢的時(shí)間控制
短輪詢的時(shí)間控制及其重要,我們需要在直播觀眾觀看體驗(yàn)QoE和服務(wù)器壓力之間找到一個(gè)很好的平衡點(diǎn)。
輪詢的間隔時(shí)間太長(zhǎng),用戶體驗(yàn)就會(huì)下降很多,直播觀看體驗(yàn)就會(huì)變差,會(huì)有"一頓一頓"的感覺。短輪詢的頻率過高,會(huì)導(dǎo)致服務(wù)器的壓力過大,也會(huì)出現(xiàn)很多次"空輪詢",所謂的"空輪詢"就是無效輪詢,也就是在上一秒有效輪詢返回有效消息之后,間隔期直播間沒有產(chǎn)生新的消息,就會(huì)出現(xiàn)無效的輪詢。
vivo直播目前每日的輪詢次數(shù)是10+億次,晚觀看直播高峰期的時(shí)候,服務(wù)器和Redis的CPU負(fù)載都會(huì)上升,dubbo的服務(wù)提供方的線程池一直處于高水位線上,這塊需要根據(jù)機(jī)器的和Redis的實(shí)時(shí)負(fù)載的壓力,做服務(wù)器的水平擴(kuò)容和Redis Cluster的節(jié)點(diǎn)擴(kuò)容,甚至讓一些超高熱度值的直播間負(fù)載到指定的Redis Cluster集群上,做到物理隔離,享受到"VIP"服務(wù),確保各個(gè)直播間的消息相互不影響。
直播人數(shù)不一樣的直播間,輪詢的時(shí)間也是可以配置的,例如人數(shù)比較少的直播,百人以下的直播間,可以設(shè)置比較高頻的輪詢頻率,例如1.5s左右,超過300人以上的,1000人以下可以2s左右,萬人直播間可以設(shè)置2.5s左右,這些配置應(yīng)該都可以通過配置中心實(shí)時(shí)下發(fā),客戶端能夠?qū)崟r(shí)更新輪詢的時(shí)間,調(diào)整的頻率可以根據(jù)實(shí)際直播間用戶體驗(yàn)的效果,并且結(jié)合服務(wù)器的負(fù)載,找到一個(gè)輪詢間隔的相對(duì)最佳值。
短輪詢的注意點(diǎn)
1)服務(wù)端需要校驗(yàn)客戶端傳遞過來的時(shí)間戳:這一點(diǎn)非常重要,試想一下,如果觀眾在觀看直播的時(shí)候,將直播退出后臺(tái),客戶端輪詢進(jìn)程暫停,當(dāng)用戶恢復(fù)直播觀看畫面進(jìn)程的時(shí)候,客戶端傳遞過來的時(shí)間就會(huì)是非常老舊甚至過期的時(shí)間,這個(gè)時(shí)間會(huì)導(dǎo)致服務(wù)器查詢Redis時(shí)出現(xiàn)慢查,如果出現(xiàn)大量的服務(wù)器慢查的話,會(huì)導(dǎo)致服務(wù)器連接Redis的連接無法快速釋放,也會(huì)拖慢整個(gè)服務(wù)器的性能,會(huì)出現(xiàn)一瞬間大量的輪詢接口超時(shí),服務(wù)質(zhì)量和QoE會(huì)下降很多。
2)客戶端需要校驗(yàn)重復(fù)消息:在極端情況下,客戶端有可能收到重復(fù)的消息,產(chǎn)生的原因可能如下,在某一個(gè)時(shí)刻客戶端發(fā)出roomId=888888×tamp=t1的請(qǐng)求,因?yàn)榫W(wǎng)絡(luò)不穩(wěn)定或者服務(wù)器GC的原因,導(dǎo)致該請(qǐng)求處理比較慢,耗時(shí)超過2s,但是因?yàn)檩喸儠r(shí)間到了,客戶端又發(fā)出了roomId=888888×tamp=t1的請(qǐng)求,服務(wù)器返回相同的數(shù)據(jù),就會(huì)出現(xiàn)客戶端重復(fù)渲染相同的消息進(jìn)行展示,這樣也會(huì)影響用戶體驗(yàn),所以每一個(gè)客戶端有必要對(duì)重復(fù)消息進(jìn)行校驗(yàn)。
3)海量數(shù)據(jù)無法實(shí)時(shí)返回渲染的問題:設(shè)想一下,如果一個(gè)熱度極大的直播間,每秒鐘產(chǎn)生的消息量是數(shù)千或者上萬的時(shí)候,按照上面的存儲(chǔ)和查詢思路是有漏洞的,因?yàn)槲覀兠看我驗(yàn)楦鱾€(gè)因素的限制,每次只返回10~20條消息,那么我們需要很長(zhǎng)的時(shí)間才能把這熱度很多的一秒鐘的數(shù)據(jù)全部返回,這樣就會(huì)造成最新的消息無法快速優(yōu)先返回,所以輪詢返回的消息也可以按照消息優(yōu)先級(jí)進(jìn)行選擇性丟棄。
客戶端輪詢服務(wù)服務(wù)器查詢直播間的消息的好處是顯而易見的,消息的分發(fā)是非常實(shí)時(shí)和準(zhǔn)確的,很難出現(xiàn)因?yàn)榫W(wǎng)絡(luò)顫抖導(dǎo)致消息無法到達(dá)的場(chǎng)景,不過壞處也是非常明顯的,服務(wù)器在業(yè)務(wù)高峰期的負(fù)載壓力很大,如果直播間的所有消息都是通過輪詢分發(fā)的,長(zhǎng)期以往,服務(wù)器是很難通過水平擴(kuò)容的方式來達(dá)到線性增長(zhǎng)的。
3.2.2、長(zhǎng)連接
長(zhǎng)連接的架構(gòu)模型
從流程上來說,如上圖所示,整體直播長(zhǎng)連接的流程:
- 手機(jī)客戶端首先通過http請(qǐng)求長(zhǎng)連接服務(wù)器,獲取TCP長(zhǎng)連接的IP地址,長(zhǎng)連接服務(wù)器根據(jù)路由和負(fù)載策略,返回最優(yōu)的可連接的IP列表。
- 手機(jī)客戶端根據(jù)長(zhǎng)連接服務(wù)器返回的IP列表,進(jìn)行長(zhǎng)連接的客戶端的連接請(qǐng)求接入,長(zhǎng)連接服務(wù)器收到連接請(qǐng)求,進(jìn)而建立連接。
- 手機(jī)客戶端發(fā)送鑒權(quán)信息,進(jìn)行通信信息的鑒權(quán)和身份信息確認(rèn),最后長(zhǎng)連接建立完成,長(zhǎng)連服務(wù)器需要對(duì)連接進(jìn)行管理,心跳監(jiān)測(cè),斷線重連等操作。
長(zhǎng)連接服務(wù)器集群的基本架構(gòu)圖如下所示,按照地域進(jìn)行業(yè)務(wù)劃分,不同地域的終端機(jī)器按需接入;
長(zhǎng)連接建立和管理
為了使消息即時(shí)、高效、安全地觸達(dá)用戶,直播客戶端和IM系統(tǒng)建立了一條加密的全雙工數(shù)據(jù)通路,收發(fā)消息均使用該通道,當(dāng)大量用戶在線的時(shí)候,維護(hù)這些連接、保持會(huì)話,需要用到大量?jī)?nèi)存和CPU資源。
IM接入層盡量保持功能簡(jiǎn)潔,業(yè)務(wù)邏輯下沉到后面邏輯服務(wù)中進(jìn)行處理,為了防止發(fā)布的時(shí)候,重啟進(jìn)程會(huì)導(dǎo)致大量的外網(wǎng)設(shè)備重新建立連接,影響用戶體驗(yàn)。接入層提供熱更新的發(fā)布方案:連接維護(hù),賬號(hào)管理等不經(jīng)常改動(dòng)的基礎(chǔ)邏輯放入主程序中,業(yè)務(wù)邏輯采用so插件的方式嵌入到程序的,修改業(yè)務(wù)邏輯時(shí)只需要重新加載一次插件即可,可以保證與設(shè)備的長(zhǎng)連接不受影響。
長(zhǎng)連接保活
長(zhǎng)連接建立后,如果中間網(wǎng)絡(luò)斷開,服務(wù)端和客戶端都無法感知,造成假在線的情況。因此維護(hù)好這個(gè)“長(zhǎng)連接”一個(gè)關(guān)鍵的問題在于能夠讓這個(gè)“長(zhǎng)連接”能夠在中間鏈路出現(xiàn)問題時(shí),讓連接的兩端能夠快速得到通知,然后通過重連來建立新的可用連接,從而讓我們這個(gè)長(zhǎng)連接一直保持高可用狀態(tài)。IM在服務(wù)端開啟了keeplive?;钐綔y(cè)機(jī)制和在客戶端啟用了智能心跳。
- 利用keeplive?;钐綔y(cè)功能,可以探知客戶端崩潰、中間網(wǎng)絡(luò)端開和中間設(shè)備因超時(shí)刪除連接相關(guān)的連接表等意外情況,從而保證在意外發(fā)生時(shí),服務(wù)端可以釋放半打開的TCP連接。
- 客戶端啟動(dòng)智能心跳不僅能在消耗極少的電和網(wǎng)絡(luò)流量條件下,通知服務(wù)器客戶端存活狀態(tài)、定時(shí)的刷新NAT內(nèi)外網(wǎng)IP映射表,還能在網(wǎng)絡(luò)變更時(shí)自動(dòng)重連長(zhǎng)連接。
3.2.3、直播間IM消息分發(fā)
IM長(zhǎng)連接分發(fā)消息的整體流程圖
在整合客戶端,IM長(zhǎng)連接服務(wù)器模塊和直播業(yè)務(wù)服務(wù)器模塊這三個(gè)模塊的時(shí)候,整體消息的分發(fā)邏輯遵循如下的基本原則:
- 單播,群播,廣播消息所有的消息都是由直播業(yè)務(wù)服務(wù)器調(diào)用IM長(zhǎng)連接服務(wù)器的接口,將需要分發(fā)的消息分發(fā)到各個(gè)業(yè)務(wù)直播間。
- 業(yè)務(wù)服務(wù)器對(duì)直播間產(chǎn)生的事件進(jìn)行對(duì)應(yīng)的業(yè)務(wù)類型做響應(yīng)的處理,例如送禮扣減虛擬貨幣,發(fā)送公屏進(jìn)行文本健康校驗(yàn)等。
- 客戶端接受直播業(yè)務(wù)服務(wù)器的信令控制,消息是通過長(zhǎng)連接通道分發(fā)還是http短輪詢分發(fā),都是由直播業(yè)務(wù)服務(wù)器控制,客戶端屏蔽底層消息獲取的方式細(xì)節(jié),客戶端上層接受統(tǒng)一的消息數(shù)據(jù)格式,進(jìn)行對(duì)應(yīng)的業(yè)務(wù)類型消息處理渲染。
直播間成員管理和消息分發(fā)
直播間成員是直播間最重要的基礎(chǔ)元數(shù)據(jù),單個(gè)直播間的用戶量實(shí)際上是無上限的,且呈現(xiàn)大直播若干個(gè)(大于30W同時(shí)在線)、中直播間幾百個(gè)、小直播幾萬個(gè)這樣分布,如何管理直播間成員是一個(gè)直播間系統(tǒng)架構(gòu)中核心功能之一,常見的方式有如下兩種:
1.為直播間分配固定分片,用戶與具體的分片存在映射關(guān)系,每個(gè)分片中保存用戶相對(duì)隨機(jī)。
采用固定分片的方式算法實(shí)現(xiàn)簡(jiǎn)單,但是對(duì)于用戶少的直播間有可能分片承載的用戶數(shù)量少,對(duì)于用戶大的直播間有可能分片承載用戶量又比較大,固定分片存在天然伸縮性差的特點(diǎn)。
2.動(dòng)態(tài)分片,規(guī)定分片用戶數(shù),當(dāng)用戶數(shù)超過閾值時(shí),增加一個(gè)新的分片,分片數(shù)量可以隨著用戶數(shù)增加而變化。
動(dòng)態(tài)分片可以根據(jù)直播間人數(shù)自動(dòng)生成分片,滿了就開辟新片,盡量使每個(gè)分片的用戶數(shù)達(dá)到閾值,但已有分片的用戶數(shù)量隨著用戶進(jìn)出直播間變化,維護(hù)復(fù)雜度比較高。
直播間消息分發(fā)
直播間中有進(jìn)出場(chǎng)消息、文本消息、禮物消息和公屏消息等多種多樣消息,消息的重要程度不一樣,可為每個(gè)消息設(shè)定相應(yīng)的優(yōu)先級(jí)。
不同優(yōu)先級(jí)的消息放在不同的消息隊(duì)列中,高優(yōu)先級(jí)的消息優(yōu)先發(fā)送給客戶端,消息堆積超過限制時(shí),丟棄最早、低優(yōu)先級(jí)的消息。另外,直播間消息屬于實(shí)時(shí)性消息,用戶獲取歷史消息、離線消息的意義不大,消息采用讀擴(kuò)散的方式存儲(chǔ)組織。直播間消息發(fā)送時(shí),根據(jù)直播間成員分片通知對(duì)應(yīng)的消息發(fā)送服務(wù),再把消息分別下發(fā)給分片中對(duì)應(yīng)的每一個(gè)用戶,為了實(shí)時(shí)、高效地把直播間消息下發(fā)給用戶,當(dāng)用戶有多條未接收消息時(shí),下發(fā)服務(wù)采用批量下發(fā)的方式將多條消息發(fā)送給用戶。
長(zhǎng)連接的消息壓縮
在使用TCP長(zhǎng)連接分發(fā)直播間消息的時(shí)候,也需要注意消息體的大小,如果某一個(gè)時(shí)刻,分發(fā)消息的數(shù)量比較大,或者同一個(gè)消息在做群播場(chǎng)景的時(shí)候,群播的用戶比較多,IM連接層的機(jī)房的出口帶寬就會(huì)成為消息分發(fā)的瓶頸。所以如何有效的控制每一個(gè)消息的大小,壓縮每一個(gè)消息的大小,是我們也需要思考的問題,我們目前通過兩種方式來來做相關(guān)消息體結(jié)構(gòu)的優(yōu)化:
- 使用protobuf協(xié)議數(shù)據(jù)交換格式
- 相同類型的消息進(jìn)行合并發(fā)送
經(jīng)過我們線上測(cè)試,使用protobuf數(shù)據(jù)交換格式,平均每一個(gè)消息節(jié)省43%的字節(jié)大小,可以大大幫助我們節(jié)省機(jī)房出口帶寬。
塊消息
所謂塊消息,也是我們借鑒其他直播平臺(tái)的技術(shù)方案,也就是多個(gè)消息進(jìn)行合并發(fā)送,直播業(yè)務(wù)服務(wù)器不是產(chǎn)生一個(gè)消息就立馬調(diào)用IM長(zhǎng)連接服務(wù)器集群直接進(jìn)行消息的分發(fā)。主要思想,就是以直播間為維度,每隔1s或者2s,以勻速的時(shí)間間隔將在這個(gè)時(shí)間段業(yè)務(wù)系統(tǒng)產(chǎn)生的消息進(jìn)行分發(fā)。
每秒分發(fā)1020個(gè)消息,如果每秒中,業(yè)務(wù)服務(wù)器積累到的消息大于1020個(gè),那就按照消息的優(yōu)先級(jí)進(jìn)行丟棄,如果這10~20個(gè)消息的優(yōu)先級(jí)都比較高,例如都是禮物類型的消息,則將消息放在后一個(gè)消息塊進(jìn)行發(fā)送,這樣做的好處有如下三個(gè);
- 合并消息,可以減少傳輸多余的消息頭,多個(gè)消息一起發(fā)送,在自定義的TCP傳輸協(xié)議中,可以共用消息頭,進(jìn)一步減少消息字節(jié)數(shù)大??;
- 防止出現(xiàn)消息風(fēng)暴,直播業(yè)務(wù)服務(wù)器可以很方便的控制消息分發(fā)的速度,不會(huì)無限制的分發(fā)消息到直播客戶端,客戶端無法處理如此多的消息;
- 友好的用戶體驗(yàn),直播間的消息因?yàn)榱魉僬#秩镜墓?jié)奏比較均勻,會(huì)帶來很好的用戶直播體驗(yàn),整個(gè)直播效果會(huì)很流暢
3.3、消息丟棄
不管是http短輪詢還是長(zhǎng)連接,在高熱度值直播間出現(xiàn)的時(shí)候,都會(huì)存在消息丟棄的情況,例如在游戲直播中,有出現(xiàn)比較精彩瞬間的時(shí)候,評(píng)論公屏數(shù)會(huì)瞬間增加,同時(shí)送低價(jià)值的禮物的消息也會(huì)瞬間增加很多,用來表示對(duì)自己選手精彩操作的支持,那么服務(wù)器通過IM長(zhǎng)連接或者h(yuǎn)ttp短輪詢每秒分發(fā)的消息數(shù)就會(huì)數(shù)千或者上萬,一瞬間的消息突增,會(huì)導(dǎo)致客戶端出現(xiàn)如下幾個(gè)問題;
- 客戶端通過長(zhǎng)連接獲取的消息突增,下行帶寬壓力突增,其他業(yè)務(wù)可能會(huì)受到影響(例如禮物的svga無法及時(shí)下載播放);
- 客戶端無法快速處理渲染如此多的禮物和公屏消息,CPU壓力突增,音視頻處理也會(huì)受到影響;
- 因消息存在積壓,導(dǎo)致會(huì)展示過期已久消息的可能,用戶體驗(yàn)(QoE)指標(biāo)會(huì)下降。
所以,因?yàn)檫@些原因,消息是存在丟棄的必要的,舉一個(gè)簡(jiǎn)單的例子,禮物的優(yōu)先級(jí)一定是高于公屏消息的,PK進(jìn)度條的消息一定是高于全網(wǎng)廣播類消息的,高價(jià)值禮物的消息又高于低價(jià)值禮物的消息。
根據(jù)這些業(yè)務(wù)理論,我們?cè)谡鎸?shí)代碼開發(fā)中,可以做如下的控制:
結(jié)合具體業(yè)務(wù)特點(diǎn),給各個(gè)業(yè)務(wù)類型的消息劃分出不同等級(jí),在消息分發(fā)觸發(fā)流控的時(shí)候,根據(jù)消息優(yōu)先級(jí)選擇性丟棄低優(yōu)先級(jí)消息。
消息結(jié)構(gòu)體新增創(chuàng)建時(shí)間和發(fā)送時(shí)間兩個(gè)字段,在實(shí)際調(diào)用長(zhǎng)連接通道的時(shí)候,需要判斷當(dāng)前時(shí)間與消息的創(chuàng)建時(shí)間是夠間隔過大,如果過大,則直接丟棄消息。
增益消息(糾正消息),在業(yè)務(wù)開發(fā)中,消息的設(shè)計(jì)中,盡量地去設(shè)計(jì)增益消息,增益消息指的是后續(xù)到達(dá)的消息能夠包含前續(xù)到達(dá)的消息,舉例來說,9點(diǎn)10的消息,主播A和主播B的PK值是20比10,那么9點(diǎn)11分分發(fā)的PK消息值就是22比10,而不能分發(fā)增量消息2:0,希望客戶端做PK條的累加(20+2 :10+0),但是存在消息因?yàn)榫W(wǎng)絡(luò)顫抖或者前置消息丟棄,導(dǎo)致消息丟棄,所以分發(fā)增益消息或者糾正消息會(huì)能夠幫助業(yè)務(wù)重新恢復(fù)正常。
四、寫在最后
任何一個(gè)直播系統(tǒng),隨著業(yè)務(wù)的發(fā)展和直播間人氣不斷的增加,消息系統(tǒng)遇到的問題和挑戰(zhàn)也會(huì)隨之而來,不管是長(zhǎng)連接的消息風(fēng)暴,還是海量http短輪詢的請(qǐng)求,都會(huì)導(dǎo)致服務(wù)器壓力的劇增,都是我們需要不斷解決和優(yōu)化的。我們要針對(duì)每一個(gè)時(shí)期的業(yè)務(wù)特點(diǎn),做直播消息的持續(xù)升級(jí),做可演進(jìn)的消息模塊,確保消息分發(fā)的能力能夠確保業(yè)務(wù)的持續(xù)發(fā)展。
vivo直播消息模塊也是逐步演進(jìn)的,演進(jìn)的動(dòng)力主要來自于因?yàn)闃I(yè)務(wù)的發(fā)展,隨著業(yè)務(wù)形態(tài)的多樣化,觀看的用戶數(shù)越來越多,系統(tǒng)的功能也會(huì)逐步增多,也會(huì)遇到各種性能瓶頸,為了解決實(shí)際遇到的性能問題,會(huì)逐一進(jìn)行代碼分析,接口性能瓶頸的分析,然后給出對(duì)應(yīng)的解決方案或者解耦方案,消息模塊也不例外,希望這篇文章能夠給大家?guī)硐嚓P(guān)直播消息模塊的設(shè)計(jì)啟發(fā)。
以上就是詳解玩轉(zhuǎn)直播系列之消息模塊演進(jìn)的詳細(xì)內(nèi)容,更多關(guān)于直播消息模塊演進(jìn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
go語言LeetCode題解720詞典中最長(zhǎng)的單詞
這篇文章主要為大家介紹了go語言LeetCode題解720詞典中最長(zhǎng)的單詞,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Go語言同步與異步執(zhí)行多個(gè)任務(wù)封裝詳解(Runner和RunnerAsync)
這篇文章主要給大家介紹了關(guān)于Go語言同步與異步執(zhí)行多個(gè)任務(wù)封裝(Runner和RunnerAsync)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究
這篇文章主要介紹了Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01詳解Go語言中如何通過Goroutine實(shí)現(xiàn)高并發(fā)
在Go語言中,并發(fā)編程是一個(gè)核心且強(qiáng)大的特性,Go語言通過goroutine和channel等機(jī)制,使得并發(fā)編程變得更加簡(jiǎn)單和直觀,本文給大家介紹了Go語言中如何通過Goroutine快速實(shí)現(xiàn)高并發(fā),感興趣的小伙伴跟著小編一起來看看吧2024-10-10