B站千萬級(jí)長連接實(shí)時(shí)消息系統(tǒng)的架構(gòu)設(shè)計(jì)與實(shí)踐
Posted on 2024-05-16 11:44 Jack Jiang 閱讀(103) 評(píng)論(0) 編輯 收藏本文由嗶哩嗶哩資深開發(fā)工程師黃山成分享,原題“千萬長連消息系統(tǒng)”,本文進(jìn)行了排版和內(nèi)容優(yōu)化等。
1、引言
在當(dāng)今數(shù)字娛樂時(shí)代,彈幕已經(jīng)成為直播平臺(tái)上不可或缺的互動(dòng)元素之一。

用戶通過發(fā)送彈幕、送禮等,可以實(shí)時(shí)在直播畫面上展現(xiàn)自己的想法、評(píng)論和互動(dòng)內(nèi)容,從而豐富了用戶觀看體驗(yàn)。在這個(gè)過程中,實(shí)時(shí)向終端推送互動(dòng)信息,就需要用到長連接。
長連接,顧名思義,是應(yīng)用存活期間和服務(wù)端一直保持的網(wǎng)絡(luò)數(shù)據(jù)通道,能夠支持全雙工上下行數(shù)據(jù)傳輸。其和請(qǐng)求響應(yīng)模式的短連接服務(wù)最大的差異,在于它可以提供服務(wù)端主動(dòng)給用戶實(shí)時(shí)推送數(shù)據(jù)的能力。
本文將介紹B站基于golang實(shí)現(xiàn)的千萬級(jí)長連接實(shí)時(shí)消息系統(tǒng)的架構(gòu)設(shè)計(jì)與實(shí)踐,包括長連接服務(wù)的框架設(shè)計(jì),以及針對(duì)穩(wěn)定性與高吞吐做的相關(guān)優(yōu)化。

- 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點(diǎn)此)
(本文已同步發(fā)布于:http://www.52im.net/thread-4647-1-1.html)
2、關(guān)聯(lián)文章
- 《B站基于微服務(wù)的API網(wǎng)關(guān)從0到1的演進(jìn)之路》
- 《石墨文檔單機(jī)50萬WebSocket長連接架構(gòu)實(shí)踐》
- 《百度統(tǒng)一socket長連接組件從0到1的技術(shù)實(shí)踐》
- 《探探的IM長連接技術(shù)實(shí)踐:技術(shù)選型、架構(gòu)設(shè)計(jì)、性能優(yōu)化》
- 《愛奇藝WebSocket實(shí)時(shí)推送網(wǎng)關(guān)技術(shù)實(shí)踐》
- 《LinkedIn的Web端即時(shí)通訊實(shí)踐:實(shí)現(xiàn)單機(jī)幾十萬條長連接》
- 《一個(gè)基于長連接的安全可擴(kuò)展的訂閱/推送服務(wù)實(shí)現(xiàn)思路》
- 《魅族2500萬長連接的實(shí)時(shí)消息推送架構(gòu)的技術(shù)實(shí)踐分享》
- 《專訪魅族架構(gòu)師:海量長連接的實(shí)時(shí)消息推送系統(tǒng)的心得體會(huì)》
3、架構(gòu)設(shè)計(jì)
3.1概述
長連接服務(wù)是多業(yè)務(wù)方共同使用一條長連接。
因?yàn)樵谠O(shè)計(jì)時(shí),需要考慮到不同業(yè)務(wù)方、不同業(yè)務(wù)場(chǎng)景對(duì)長連接服務(wù)的訴求,同時(shí)也要考慮長連接服務(wù)的邊界,避免介入業(yè)務(wù)邏輯,影響后續(xù)長連接服務(wù)的迭代和發(fā)展。
長連接服務(wù)主要分為三個(gè)方面:
- 1)長連接建立、維護(hù)、管理;
- 2)下行數(shù)據(jù)推送;
- 3)上行數(shù)據(jù)轉(zhuǎn)發(fā)(目前只有心跳,還沒實(shí)際業(yè)務(wù)場(chǎng)景需求)。
3.2整體架構(gòu)

長連接服務(wù)整體構(gòu)架如上圖所示,整體服務(wù)包含以下幾個(gè)部分。
1)控制層:建連的前置調(diào)用,主要做接入合法性校驗(yàn)、身份校驗(yàn)和路由管控。
主要職責(zé):
- 1)用戶身份鑒權(quán);
- 2)加密組裝數(shù)據(jù),生成合法token;
- 3)動(dòng)態(tài)調(diào)度分配接入節(jié)點(diǎn)。
2)接入層:長連接核心服務(wù),主要做卸載證書、協(xié)議對(duì)接和長連接維護(hù)。
主要職責(zé):
- 1)卸載證書和協(xié)議;
- 2)負(fù)責(zé)和客戶端建立并維護(hù)連接,管理連接id和roomid的映射關(guān)系;
- 3)處理上下行消息。
3)邏輯層:簡化接入層,主要做長連的業(yè)務(wù)功能。
主要職責(zé):
- 1)在線人數(shù)上報(bào)記錄;
- 2)記錄連接ID各屬性和各節(jié)點(diǎn)的映射關(guān)系。
- 4)消息分發(fā)層:消息推送到接入層。
主要職責(zé):
- 1)消息封裝、壓縮和聚合推送給相應(yīng)的邊緣節(jié)點(diǎn);
5)服務(wù)層:業(yè)務(wù)服務(wù)對(duì)接層,提供下行消息推送入口。
主要職責(zé):
- 1)管控業(yè)務(wù)推送權(quán)限;
- 2)消息檢測(cè)和重組裝;
- 3)消息按一定策略限流,保護(hù)自身系統(tǒng)。
3.3核心流程

長連接主要是3個(gè)核心流程:
- 1)建立連接:由客戶端發(fā)起,先通過控制層,獲取該設(shè)備合法的token和接入點(diǎn)配置;
- 2)維持連接:主要是客戶端定時(shí)發(fā)起心跳,來保證長連接活躍;
- 3)下行推送:下行推送由業(yè)務(wù)Server發(fā)起,經(jīng)由服務(wù)層根據(jù)相關(guān)標(biāo)識(shí)確定連接標(biāo)識(shí)和接入節(jié)點(diǎn),經(jīng)過消息分發(fā)層,把推送到對(duì)應(yīng)的接入層,寫入到指定連接上,然后下發(fā)到客戶端。
3.4功能列表
結(jié)合B站業(yè)務(wù)場(chǎng)景,下行數(shù)據(jù)推送,提供如下通用功能:
- 1)用戶級(jí)消息:指定推送給某些用戶(比如給某個(gè)主播發(fā)送邀請(qǐng)pk消息);
- 2)設(shè)備級(jí)消息:制定推送給某些設(shè)備(比如針對(duì)未登陸的設(shè)備,推送客戶端日志上報(bào)指令);
- 3)房間級(jí)消息:給某房間內(nèi)的連接推送消息(比如給直播間的所有在線用戶推送彈幕消息);
- 4)分區(qū)消息:給某分區(qū)的房間推送消息(比如給某個(gè)分區(qū)下,所有開播的房間,推送某個(gè)營收活動(dòng));
- 5)全區(qū)消息:給全平臺(tái)用戶推送消息(比如給全部在線用戶推送活動(dòng)通知)。
4、高吞吐技術(shù)設(shè)計(jì)
隨著業(yè)務(wù)發(fā)展壯大,在線用戶越來越多,長連系統(tǒng)的壓力越來越大,尤其是熱門賽事直播,比如s賽期間,全平臺(tái)在線人數(shù)快達(dá)到千萬,消息吞吐量有上億,長連系統(tǒng)消息分發(fā)平均延遲耗時(shí)在1s左右,消息到達(dá)率達(dá)到99%,下面具體分析下長連做了哪些措施。
4.1網(wǎng)絡(luò)協(xié)議
選擇合適的網(wǎng)絡(luò)協(xié)議對(duì)于長連接系統(tǒng)的性能至關(guān)重要:
- 1)TCP協(xié)議:可以提供可靠的連接和數(shù)據(jù)傳輸,適用于對(duì)數(shù)據(jù)可靠性要求較高的場(chǎng)景;
- 2)UDP協(xié)議:是一個(gè)不可靠的協(xié)議,但是傳輸效率高,適用于對(duì)數(shù)據(jù)可靠性要求不高的場(chǎng)景;
- 3)WebSocket協(xié)議:也是實(shí)現(xiàn)雙向通信而不增加太多的開銷,更多的用于web端。
接入層拆分成協(xié)議模塊和連接模塊:
- 1)協(xié)議模塊:和具體的通訊層協(xié)議交互,封裝不同通訊協(xié)議的接口和邏輯差異。
- 2)連接模塊:維護(hù)長連接業(yè)務(wù)連接狀態(tài),支持請(qǐng)求上行、下行等業(yè)務(wù)邏輯,維護(hù)連接各屬性,以及和房間id的綁定關(guān)系。
針對(duì)以上第 1)點(diǎn),協(xié)議模塊同時(shí)給連接模塊提供統(tǒng)一的數(shù)據(jù)接口,包括連接建立、數(shù)據(jù)讀取、寫入等。后續(xù)增加新協(xié)議,只要在協(xié)議模塊做適配,不影響其他模塊的長連業(yè)務(wù)邏輯。
優(yōu)勢(shì)在于:
- 1)業(yè)務(wù)邏輯和通訊協(xié)議做了隔離,方便迭代增加通訊協(xié)議,簡化兼容多通訊協(xié)議的實(shí)現(xiàn)難度;
- 2)控制層可以根據(jù)客戶端的實(shí)際情況,下發(fā)更優(yōu)的通訊協(xié)議。
4.2負(fù)載均衡
采用負(fù)載均衡技術(shù)可以將請(qǐng)求分發(fā)到不同的服務(wù)器節(jié)點(diǎn)上處理,避免了單一節(jié)點(diǎn)的負(fù)載過高,提高了系統(tǒng)的擴(kuò)展性和穩(wěn)定性。
長連增加控制層,做負(fù)載均衡??刂茖犹峁﹉ttp短連接口,基于客戶端和各邊緣節(jié)點(diǎn)實(shí)際情況,根據(jù)就近原則,動(dòng)態(tài)選擇合適的接入節(jié)點(diǎn)。
接入層支持水平擴(kuò)展,控制層可以實(shí)時(shí)增加、減少分配節(jié)點(diǎn)。在S賽期間,在線人數(shù)快到達(dá)千萬時(shí),平衡調(diào)度各接入節(jié)點(diǎn),保障了各節(jié)點(diǎn)的CPU和內(nèi)存都在穩(wěn)定的范圍內(nèi)。
4.3消息隊(duì)列
消息推送鏈路是:業(yè)務(wù)發(fā)送推送,經(jīng)過服務(wù)層推到邊緣節(jié)點(diǎn),然后下發(fā)給客戶端。
服務(wù)層實(shí)時(shí)分發(fā)到各邊緣節(jié)點(diǎn),如果是房間類型消息,需要推到多個(gè)邊緣節(jié)點(diǎn),服務(wù)層同時(shí)還要處理業(yè)務(wù)邏輯,很影響消息的吞吐量。
所以增加消息隊(duì)列和消息分發(fā)層,消息分發(fā)層維護(hù)各邊緣節(jié)點(diǎn)信息和推送消息,提高了系統(tǒng)的并發(fā)處理能力和穩(wěn)定性,避免了因消息推送阻塞而導(dǎo)致的性能問題。
4.4消息聚合
當(dāng)有熱門賽事時(shí),同時(shí)在線可能達(dá)到千萬級(jí)別,一條彈幕消息就要擴(kuò)散到千萬個(gè)終端,假如在線的每個(gè)人每秒發(fā)一條,需要發(fā)送消息量就是1kw*1kw,消息量非常大,此時(shí)消息分發(fā)層和接入層,壓力都會(huì)很大。
分析發(fā)現(xiàn):這些消息都是同一個(gè)房間的,屬于熱點(diǎn)房間,比如s賽房間,觀眾數(shù)量是無法減少的,那只能在消息數(shù)上做文章。業(yè)務(wù)消息推送不能減少,又要減少擴(kuò)散的消息數(shù),就想到了消息聚合。
針對(duì)房間消息,按照一定的規(guī)則進(jìn)行消息聚合,批量推送:

消息聚合上線后,消息分發(fā)層對(duì)接入層調(diào)用QPS下降60%左右,極大的降低了接入層和消息分發(fā)層的壓力。
4.5壓縮算法
消息聚合后,降低了消息的數(shù)量,但是增加了消息體的大小,影響了寫入IO,需要減少消息體大小,就想到了消息壓縮。
壓縮算法,選了市面上比較常用的兩個(gè):zlib和brotli,進(jìn)行比較。
抓取了線上業(yè)務(wù)推送的數(shù)據(jù),選擇最高等級(jí)的壓縮等級(jí),進(jìn)過壓縮驗(yàn)證:

由此可見,brotli相比zlib有很大的優(yōu)勢(shì),最后選擇了brotli壓縮算法。
選擇在消息分發(fā)層進(jìn)行消息壓縮,避免在各接入節(jié)點(diǎn)多次重復(fù)壓縮,浪費(fèi)性能。上線后提升吞吐量的同時(shí),也降低的寬帶使用成本。
5、服務(wù)保障技術(shù)設(shè)計(jì)
現(xiàn)在有些業(yè)務(wù)是強(qiáng)依賴長連推送消息,消息丟失,輕則影響用戶體驗(yàn),重則阻塞業(yè)務(wù)后續(xù)流程,進(jìn)而影響業(yè)務(wù)流水。針對(duì)長連服務(wù)消息保障,做了如下工作。
5.1多活部署
多活部署,通過在不同地理位置部署相同的系統(tǒng)架構(gòu)和服務(wù),實(shí)現(xiàn)了系統(tǒng)在單一地域故障時(shí)的快速故障轉(zhuǎn)移,從而提高了系統(tǒng)的穩(wěn)定性和可用性。

長連服務(wù)部署,主要做了以下幾點(diǎn):
- 1)長連接在國內(nèi)華東、華南、華北地域均部署了接入點(diǎn),支持三大運(yùn)營商;華南和華中自建機(jī)房也部署了接入點(diǎn);為支持海外用戶,增加了新加坡機(jī)房獨(dú)立接入點(diǎn);
- 2)針對(duì)業(yè)務(wù)場(chǎng)景不同,在云上節(jié)點(diǎn)和自建節(jié)點(diǎn)之間,實(shí)時(shí)切換,因?yàn)樵粕瞎?jié)點(diǎn)和自建機(jī)房的成本是不一樣的,在保證服務(wù)質(zhì)量的前提下,盡可能的控制成本。
目前線上運(yùn)行過程中,偶爾會(huì)遇到單節(jié)點(diǎn)或機(jī)房的網(wǎng)絡(luò)抖動(dòng),通過控制層,對(duì)有問題的節(jié)點(diǎn),進(jìn)行秒級(jí)摘流,大大減少了對(duì)業(yè)務(wù)的影響。
5.2高低消息通道
多業(yè)務(wù)消息接入長連接,但不同消息之間的重要性是不一樣的,比如彈幕消息和邀請(qǐng)pk消息,丟失幾條彈幕對(duì)用戶體驗(yàn)不會(huì)影響很大,但如果邀請(qǐng)pk消息丟失,則會(huì)導(dǎo)致pk業(yè)務(wù)無法進(jìn)行后續(xù)的流程。
針對(duì)不同等級(jí)的消息,采用了高低優(yōu)消息通道。重要消息走高優(yōu)通道,普通消息走低優(yōu)通道。這樣重要和普通消息進(jìn)行了物理隔離,消息分發(fā)優(yōu)先保證重要消息。

針對(duì)高優(yōu)通道,做了雙投遞的保障,在接入層做冪等去重。首先重要消息是針對(duì)用戶級(jí)別的,量不會(huì)很大,所以對(duì)接入層的壓力不會(huì)增加很大。另外雙投遞的job是部署在多機(jī)房的,這也就降低單機(jī)房網(wǎng)絡(luò)抖動(dòng)造成的影響。
高低優(yōu)通道上線后,遇到過內(nèi)網(wǎng)出網(wǎng)抖動(dòng),當(dāng)時(shí)內(nèi)網(wǎng)部屬的job節(jié)點(diǎn)推送消息異常,而云上高優(yōu)job節(jié)點(diǎn)可正常推送,很好的保障了高優(yōu)消息的到達(dá),進(jìn)而保障了高優(yōu)業(yè)務(wù)不受影響。
5.3高達(dá)功能
高低優(yōu)通道解決的是job到接入層的這一個(gè)環(huán)節(jié),但消息推送聯(lián)路涉及到多個(gè)環(huán)節(jié),比如服務(wù)層到j(luò)ob、接入層到客戶端。
針對(duì)整個(gè)鏈路,通過實(shí)現(xiàn)必達(dá)機(jī)制來確保終端的到達(dá)率,簡稱高達(dá)功能。

功能實(shí)現(xiàn):
- 1)每條消息引入msgID,客戶端收到消息后進(jìn)行冪等去重和ack回執(zhí);
- 2)服務(wù)端針對(duì)msgid進(jìn)行ack檢測(cè),針對(duì)未ack的,有效期內(nèi)再次重試下發(fā)。
最終到達(dá)率 = (1-(1-r)^(n+1)),其中:r為廣播單次到達(dá)率,n為最大重試次數(shù)。
例如:r = 97%、n=2,那么最終到達(dá)率可以達(dá)到(1-(1-0.97)^(2+1)) = 99.9973%
6、進(jìn)出”房“消息的送達(dá)保證設(shè)計(jì)
有些業(yè)務(wù)場(chǎng)景,需要用到用戶進(jìn)出房消息,比如用戶A進(jìn)入直播間,頁面會(huì)顯示歡迎用戶A進(jìn)入房間,或者是加入在線榜單。
1)進(jìn)房消息會(huì)存在丟失,需要有補(bǔ)償機(jī)制。想到可以通過連接心跳來補(bǔ)償進(jìn)房消息,但心跳是持續(xù)不斷的,連接在線期間,業(yè)務(wù)希望只收到一次進(jìn)房消息,所以進(jìn)房消息需要有冪等機(jī)制。
2)出房消息也會(huì)存在丟失,如果丟失了,業(yè)務(wù)無法從在線榜單剔除用戶,此時(shí)也需要有補(bǔ)償機(jī)制。此時(shí)就需要增加連接的狀態(tài)機(jī),通過心跳維護(hù)狀態(tài)機(jī),當(dāng)心跳丟失時(shí),認(rèn)為連接斷開,用戶退房。

7、未來規(guī)劃
統(tǒng)一長連接服務(wù)經(jīng)歷數(shù)次迭代后,目前基本功能已經(jīng)趨于穩(wěn)定,后續(xù)對(duì)長連接服務(wù)進(jìn)行改善和優(yōu)化。
主要集中在以下幾個(gè)方向:
- 1)數(shù)據(jù)化:進(jìn)一步完善長連接全鏈路網(wǎng)絡(luò)質(zhì)量數(shù)據(jù)統(tǒng)計(jì)和高價(jià)值消息全鏈路追蹤的能力;
- 2)智能化:端上建聯(lián)、接入點(diǎn)選擇等能夠根據(jù)實(shí)際環(huán)境進(jìn)行自動(dòng)化調(diào)整;
- 3)性能優(yōu)化:接入層的連接模塊中,處理上下行消息的攜程進(jìn)行共享,減少接入層的攜程數(shù),進(jìn)一步提升單機(jī)性能和連接數(shù);
- 4)功能擴(kuò)展:新增離線消息功能等。
8、參考資料
[2] 正確理解IM長連接、心跳及重連機(jī)制,并動(dòng)手實(shí)現(xiàn)
[3] 萬字長文:手把手教你實(shí)現(xiàn)一套高效的IM長連接自適應(yīng)心跳?;顧C(jī)制
[4] 用JWT技術(shù)解決IM系統(tǒng)Socket長連接的身份認(rèn)證痛點(diǎn)
[5] TCP/IP詳解 - 第11章·UDP:用戶數(shù)據(jù)報(bào)協(xié)議
[6] TCP/IP詳解 - 第17章·TCP:傳輸控制協(xié)議
[7] WebSocket從入門到精通,半小時(shí)就夠!
[9] 快速理解TCP和UDP的差異
[10] 一泡尿的時(shí)間,快速搞懂TCP和UDP的區(qū)別
[11] 到底什么是Socket?一文即懂!
[12] 我們?cè)谧x寫Socket時(shí),究竟在讀寫什么?
[13] 假如你來設(shè)計(jì)TCP協(xié)議,會(huì)怎么做?
[14] 深入操作系統(tǒng),一文搞懂Socket到底是什么
[15] 通俗易懂,高性能服務(wù)器到底是如何實(shí)現(xiàn)的
[16] 12306搶票帶來的啟示:看我如何用Go實(shí)現(xiàn)百萬QPS的秒殺系統(tǒng)(含源碼)
(本文已同步發(fā)布于:http://www.52im.net/thread-4647-1-1.html)
作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
出處:http://www.52im.net/space-uid-1.html
交流:歡迎加入即時(shí)通訊開發(fā)交流群 215891622
討論:http://www.52im.net/
Jack Jiang同時(shí)是【原創(chuàng)Java
Swing外觀工程BeautyEye】和【輕量級(jí)移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
本博文
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處(也可前往 我的52im.net 找到我)。