高并發(fā)實(shí)時(shí)彈幕是一種互動(dòng)的體驗(yàn)。對(duì)于互動(dòng)來說,考慮最多的地方就是:高穩(wěn)定性、高可用性以及低延遲這三個(gè)方面。
網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了陽新免費(fèi)建站歡迎大家使用!高穩(wěn)定性,為了保證互動(dòng)的實(shí)時(shí)性,所以要求連接狀態(tài)穩(wěn)定;
高可用性,相當(dāng)于提供一種備用方案,比如,互動(dòng)時(shí)如果一臺(tái)機(jī)器掛了,此時(shí)必須保證可以和另外一臺(tái)機(jī)器連接,這樣就從側(cè)面解決了,用戶連接不中斷的問題;
低延遲,彈幕的延遲周期控制在1秒以內(nèi),響應(yīng)是比較快的,所以可以滿足互動(dòng)的需求。
B站直播彈幕服務(wù)架構(gòu)(下面簡稱GOIM)的出現(xiàn)就是為了解決這一系列的需求。下面將對(duì)此進(jìn)行詳細(xì)的介紹。
直播聊天系統(tǒng)本質(zhì)上也是一種推送系統(tǒng),所謂推送系統(tǒng)就是,當(dāng)你發(fā)送一條消息時(shí),它可以將這個(gè)消息推送給所有人。對(duì)于直播彈幕來說,用戶在不斷的發(fā)送消息,不斷的進(jìn)行廣播,當(dāng)一個(gè)房間里面有10萬人時(shí),一個(gè)消息就要發(fā)出10萬次請(qǐng)求。在GOIM出現(xiàn)之前,也用過另一個(gè)名為Gopush的項(xiàng)目,這個(gè)項(xiàng)目推出的目的就是進(jìn)行推送。在此之后,基于一些針對(duì)性的應(yīng)用場景,GOIM對(duì)Gopush進(jìn)行了優(yōu)化,從而出現(xiàn)在我們視野當(dāng)中。GOIM主要包含以下幾個(gè)模塊(圖1):
1. Client
客戶端。與Comet建立鏈接。
2. Comet
維護(hù)客戶端長鏈接。在上面可以規(guī)定一些業(yè)務(wù)需求,比如可以規(guī)定用戶傳送的信息的內(nèi)容、輸送用戶信息等。Comet提供并維持服務(wù)端與客戶端之間的鏈接,這里保證鏈接可用性的方法主要是發(fā)送鏈接協(xié)議(如Socket等)。
3. Logic
對(duì)消息進(jìn)行邏輯處理。用戶建立連接之后會(huì)將消息轉(zhuǎn)發(fā)給Logic,在Logic上可以進(jìn)行賬號(hào)驗(yàn)證。當(dāng)然,類似于IP過濾以及黑名單設(shè)置此類的操作也可以經(jīng)由Logic進(jìn)行。
4. Router
存儲(chǔ)消息。Comet將信息傳送給Logic之后,Logic會(huì)對(duì)所收到的信息進(jìn)行存儲(chǔ),采用register session的方式在Router上進(jìn)行存儲(chǔ)。Router里面會(huì)收錄用戶的注冊(cè)信息,這樣就可以知道用戶是與哪個(gè)機(jī)器建立的連接。
5. Kafka(第三方服務(wù))
消息隊(duì)列系統(tǒng)。Kafka是一個(gè)分布式的基于發(fā)布/訂閱的消息系統(tǒng),它是支持水平擴(kuò)展的。每條發(fā)布到Kafka集群的消息都會(huì)打上一個(gè)名為Topic(邏輯上可以被認(rèn)為是一個(gè)queue)的類別,起到消息分布式分發(fā)的作用。
6. Jop
消息分發(fā)。可以起多個(gè)Jop模塊放到不同的機(jī)器上進(jìn)行覆蓋,將消息收錄之后,分發(fā)到所有的Comet上,之后再由Comet轉(zhuǎn)發(fā)出去。
以上就是GOIM系統(tǒng)實(shí)現(xiàn)客戶端建立鏈接,并進(jìn)行消息轉(zhuǎn)發(fā)的一個(gè)具體過程。一開始這個(gè)結(jié)構(gòu)并不完善,在代碼層面也存在一些問題。鑒于這些問題,B站提供了一些相關(guān)的優(yōu)化操作。在高穩(wěn)定性方面,提供了內(nèi)存優(yōu)化、模塊優(yōu)化以及網(wǎng)絡(luò)優(yōu)化,下面是對(duì)這些優(yōu)化操作的介紹。
內(nèi)存優(yōu)化
內(nèi)存優(yōu)化主要分為以下三個(gè)方面:
一個(gè)消息一定只有一塊內(nèi)存
使用Job聚合消息,Comet指針引用
一個(gè)用戶的內(nèi)存盡量放到棧上
內(nèi)存創(chuàng)建在對(duì)應(yīng)的用戶Goroutine(Go程)中
內(nèi)存由自己控制
主要是針對(duì)Comet模塊所做的優(yōu)化,可以查看模塊中各個(gè)分配內(nèi)存的地方,使用內(nèi)存池
模塊優(yōu)化
模塊優(yōu)化也分為以下三方面:
消息分發(fā)一定是并行的并且互不干擾
要保證到每一個(gè)Comet的通訊通道必須是相互獨(dú)立的,保證消息分發(fā)必須是完全并列的,并且彼此之間互不干擾。
并發(fā)數(shù)一定是可以進(jìn)行控制的
每個(gè)需要異步處理開啟的Goroutine(Go協(xié)程)都必須預(yù)先創(chuàng)建好固定的個(gè)數(shù),如果不提前進(jìn)行控制,那么Goroutine就隨時(shí)存在爆發(fā)的可能。
全局鎖一定是被打散的
Socket鏈接池管理、用戶在線數(shù)據(jù)管理都是多把鎖;打散的個(gè)數(shù)通常取決于CPU,往往需要考慮CPU切換時(shí)造成的負(fù)擔(dān),并非是越多越好。
模塊優(yōu)化的三個(gè)方面,主要考慮的問題就是,分布式系統(tǒng)中會(huì)出現(xiàn)的單點(diǎn)問題,即當(dāng)一個(gè)用戶在建立鏈接后,如果出現(xiàn)故障,其余用戶建立的鏈接不能被影響。
測試是實(shí)踐過程中最不可缺少的一部分,同時(shí),測試的數(shù)據(jù)也是用來進(jìn)行參考比照的最好工具。
圖2是15年末的壓測數(shù)據(jù)。當(dāng)時(shí)使用了兩臺(tái)物理機(jī),平均每臺(tái)的在線量是25萬,每個(gè)直播每秒的推送數(shù)量控制在20-50條內(nèi)。一般對(duì)于一個(gè)屏幕來說,40條就可以滿足直播的需求,當(dāng)時(shí)用來進(jìn)行模擬的推送量是50條/秒(峰值),推送到達(dá)數(shù)是2440萬/秒。這次的數(shù)據(jù)顯示,CPU的負(fù)載是剛好滿,內(nèi)存使用量在4G左右,流量約為 3G。從這個(gè)數(shù)據(jù)得出的結(jié)論是,真正的瓶頸負(fù)載在CPU上。所以,目的很明確,就是將CPU負(fù)載打滿(但是不能超負(fù)載)。
2015年之后,再次進(jìn)行優(yōu)化,將所有內(nèi)存(堆上的、不可控的)都遷移到棧上,當(dāng)時(shí)只采用了一臺(tái)物理機(jī),上面承載了100萬的在線數(shù)量。優(yōu)化效果體現(xiàn)在16年3月的壓測數(shù)據(jù)(圖3)中,這個(gè)數(shù)據(jù)也是最初直播時(shí),想要測試的一個(gè)壓縮狀況。
從圖 3的數(shù)據(jù)可以看出,優(yōu)化效果是成倍增加的。當(dāng)時(shí)的目的也是將CPU打滿,可是在實(shí)際直播環(huán)境中,需要考慮的最本質(zhì)的問題其實(shí)是在流量上,包括彈幕字?jǐn)?shù)、贈(zèng)送禮物的數(shù)量。如果彈幕需要加上一些特殊的需求(字體、用戶等級(jí)等),贈(zèng)送禮物數(shù)量過多這樣,都會(huì)產(chǎn)生很多流量。所以,直播彈幕優(yōu)化的最終瓶頸只有流量。
2016年之前,B站的優(yōu)化重點(diǎn)都放在了系統(tǒng)的優(yōu)化上,包括優(yōu)化內(nèi)存,降低CPU的使用率,可是優(yōu)化的效果并不顯著,一臺(tái)機(jī)器的瓶頸永遠(yuǎn)是流量。在2016年3月份后,B站將優(yōu)化重點(diǎn)轉(zhuǎn)移到了網(wǎng)絡(luò)優(yōu)化上。下面就是B站網(wǎng)絡(luò)優(yōu)化的一些措施。
網(wǎng)絡(luò)優(yōu)化
最初B站的工作內(nèi)容,主要是以開發(fā)為主,為了在結(jié)構(gòu)上面得到擴(kuò)展,所做的工作就是將代碼盡量完善。但是在實(shí)際業(yè)務(wù)當(dāng)中,也會(huì)遇見更多運(yùn)維方面的問題,所以,在之后的關(guān)注重點(diǎn)上,B站添加了對(duì)運(yùn)維的重點(diǎn)關(guān)注。
圖4是B站早期的部署結(jié)構(gòu)。最開始,整套服務(wù)是部署在一個(gè)IDC上面的(單點(diǎn)IDC),時(shí)間一長,這樣的部署結(jié)構(gòu)也逐漸顯現(xiàn)出它的缺陷:
單線IDC流量不足
單點(diǎn)問題
接入率低
這樣的網(wǎng)絡(luò)部署往往會(huì)造成延遲高、網(wǎng)速卡頓等問題。
針對(duì)以上三點(diǎn)問題,B站也對(duì)部署結(jié)構(gòu)進(jìn)行了改善,圖 5是改善過的網(wǎng)絡(luò)部署結(jié)構(gòu),下面將對(duì)這個(gè)部署結(jié)構(gòu)進(jìn)行詳細(xì)說明。
針對(duì)單點(diǎn)IDC流量不足的問題,B站采用了多點(diǎn)IDC接入的方案。一個(gè)機(jī)房的流量不夠,那么就把它分散到不同的機(jī)房,看看效果如何。
對(duì)于多點(diǎn)IDC接入來說,專線的成本是非常高昂的,對(duì)于創(chuàng)業(yè)公司來說,是一塊很大的負(fù)擔(dān),所以可以通過一些研發(fā)或者是架構(gòu)的方式來解決多IDC的問題 。針對(duì)多IDC的問題,需要優(yōu)化的方面還有很多,下面列舉出一些B站現(xiàn)有的一些優(yōu)化方案:
調(diào)節(jié)用戶最優(yōu)接入節(jié)點(diǎn)
使用Svrlist模塊(圖6.1 )支持,選取距離用戶最近的最穩(wěn)定的節(jié)點(diǎn),調(diào)控IP段,然后進(jìn)行接入。
IDC 的服務(wù)質(zhì)量監(jiān)控:掉線率
判斷一個(gè)節(jié)點(diǎn)是否穩(wěn)定,需要不斷收集大量的用戶鏈接信息,此時(shí)就可以使用監(jiān)控來查詢掉線率,然后不斷調(diào)優(yōu),收集最終的結(jié)果去做一個(gè)拓?fù)鋱D(全國范圍),在拓?fù)鋱D當(dāng)中就可以判斷出城市到機(jī)房之間的最優(yōu)線路。
自動(dòng)切走“失聯(lián)”服務(wù)器
消息100%的到達(dá)率(仍在實(shí)現(xiàn)中)
對(duì)于彈幕來說,低丟包率是非常重要的。比如,消息是價(jià)值上千塊的禮物,此時(shí)一旦丟失某些消息,當(dāng)用戶發(fā)禮物時(shí),起到的效果就是,實(shí)際在彈幕中顯示出來的效果是,禮物數(shù)遠(yuǎn)遠(yuǎn)少于用戶花費(fèi)金錢買來的禮物數(shù)。這是一個(gè)很嚴(yán)重的問題。
流量控制
對(duì)于彈幕來說,當(dāng)用戶量到達(dá)一定級(jí)別時(shí),需要考慮的問題還是流量控制,這也是對(duì)于花銷成本的控制,當(dāng)買的機(jī)房的帶寬,是以千兆帶寬為計(jì)費(fèi)標(biāo)準(zhǔn)時(shí),當(dāng)有超標(biāo)時(shí),一定要將超標(biāo)部分的流量切走,以此實(shí)現(xiàn)了流量控制的功能。
引入多點(diǎn)IDC接入之后,電信的用戶依舊可以走電信的線路,但是可以將模塊在其他機(jī)房進(jìn)行部署,讓移動(dòng)的一些用戶可以連接移動(dòng)的機(jī)房。這樣就保證了,不同地區(qū)不同運(yùn)營商之間,最優(yōu)網(wǎng)絡(luò)選取的問題。
可是解決了最優(yōu)網(wǎng)絡(luò)的選取,卻帶來了跨域傳輸?shù)膯栴}。比如在數(shù)據(jù)收集時(shí),Comet模塊將數(shù)據(jù)反饋到Logic,Logic進(jìn)行消息分發(fā)時(shí),數(shù)據(jù)便會(huì)跨機(jī)房傳輸。有些公司的機(jī)房是通過專線進(jìn)行傳輸,這樣成本將會(huì)非常高。所以,為了節(jié)約成本就只能走公網(wǎng)的流量,但是公網(wǎng)的穩(wěn)定性是否高、是否高可用,都是需要考慮的。當(dāng)流量從電信的機(jī)房出去之后,經(jīng)過電信的交換機(jī),轉(zhuǎn)到聯(lián)通的交換機(jī),然后到達(dá)聯(lián)通的機(jī)房,就會(huì)存在跨運(yùn)營商傳輸?shù)膯栴},比如丟包率高,因此,跨運(yùn)營商傳輸帶來的問題還是非常嚴(yán)重的。
為了解決這個(gè)可能存在的風(fēng)險(xiǎn),可以嘗試在聯(lián)通機(jī)房接入一條電信的線路(帶寬可以小一點(diǎn)),“看管”電信的模塊,讓來自不同運(yùn)營商的流量,可以走自己的線路。做了這樣的嘗試之后,不僅降低了丟包率,還滿足了對(duì)穩(wěn)定性的基本要求,并且成本消耗也不高??墒牵@樣的方案也不能說是百分百的完美,因?yàn)榫退闶峭\(yùn)營商之間的通訊,也會(huì)存在城市和城市之間某個(gè)交換機(jī)出現(xiàn)故障的情況,對(duì)于這樣的情況,B站采取的方法是同時(shí)在IDC-1與IDC-2(圖 5)之間部署兩條電信線路,做了這樣的備份方案之后,通暢程度以及穩(wěn)定性都有非常明顯的提升。
針對(duì)上述過程中出現(xiàn)的一些問題,前期,需要對(duì)每個(gè)線路的穩(wěn)定性進(jìn)行測試。為了測試每一條線路的穩(wěn)定性,可以把Comet放入各個(gè)機(jī)房中,并將Comet之間的通訊方式匯總成一個(gè)鏈接池(鏈接池里可以放多個(gè)運(yùn)營商的多條線路),作為網(wǎng)絡(luò)鏈接可以將它配置成多條線路,用模塊檢測所有的Comet之間的通訊,以及任何線路傳輸?shù)姆€(wěn)定性,如果說通暢的話,則保證這個(gè)鏈接是可以用的(這里面有很多線路,所以一定會(huì)選擇通暢的那條線路進(jìn)行傳輸,這樣,就可以判斷哪條線路是通暢的)這樣一來,流量進(jìn)行傳輸時(shí),就有多條線路可以進(jìn)行選擇,三個(gè)運(yùn)營商中,總有一個(gè)是可以服務(wù)的。
綜合這些問題,B站又對(duì)結(jié)構(gòu)進(jìn)行了重新優(yōu)化(這個(gè)結(jié)構(gòu)剛剛做完,目前還沒有上線,還需要經(jīng)過一些測試)。
首先是Comet的鏈接,之前采用的是CDN、智能DNS。但實(shí)際上,有些運(yùn)營商基站會(huì)緩存路由表,所以即便將機(jī)器遷移走,部分用戶也并不能同時(shí)遷移走。而DNS解析這一塊,也并非完全可靠,而且一旦遇上問題,解決的流程又很長,這樣下來,體驗(yàn)效果是十分糟糕的。其次是List,將其部署在一個(gè)中心機(jī)房,客戶端采用的是WEB接口的服務(wù),讓客戶端訪問這個(gè)服務(wù),就可以知道該與哪些服務(wù)器進(jìn)行連接。將IP List( Comet )部署在多個(gè)機(jī)房,可以將多個(gè)機(jī)房收集的值反饋給客戶端(比如:哪些線路通暢)讓客戶端自己選擇與那個(gè)機(jī)器進(jìn)行連接。
如圖6.2,圖中將IP段進(jìn)行了城市的劃分,將某一個(gè)城市的一些用戶信息鏈接到一個(gè)群組(GroupID),群組下有一個(gè)或多個(gè)Comet,把屬于這個(gè)群組的物理機(jī)全部分給Comet。
圖7是再次優(yōu)化的結(jié)構(gòu),還是將Comet全部放在IDC機(jī)房中,消息的傳輸不再使用push(推)的方式,而是通過pull(拉)的方式,將數(shù)據(jù)拉到中心機(jī)房(源站),做一些在線處理之后,再統(tǒng)一由源站進(jìn)行數(shù)據(jù)推送。當(dāng)然,這里要十分注意中心機(jī)房的選取,中心機(jī)房的穩(wěn)定性是十分重要的。除此之外,B站在部署的時(shí)候還優(yōu)化了故障監(jiān)控這塊功能,用來保證高可用的服務(wù)。故障監(jiān)控主要為以下幾項(xiàng):
模擬 Client ,監(jiān)控消息到達(dá)的速率
線上開啟 Ppof ,隨時(shí)抓圖分析進(jìn)程(CPU )狀況
白名單:指定人打印服務(wù)端日志
設(shè)置白名單,記錄日志信息,收集問題反饋
標(biāo)注重點(diǎn)問題,及時(shí)解決
防止消息重現(xiàn)
服務(wù)器負(fù)載監(jiān)控,短信報(bào)警
對(duì)于GOIM來說,低成本、高效率一直是B站所追求的標(biāo)準(zhǔn),B站也將對(duì)系統(tǒng)進(jìn)行持續(xù)優(yōu)化和改進(jìn),以給用戶最好的直播彈幕體驗(yàn)。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。