B站牛逼的實時彈幕系統架構是如何實現的
前言:隨著直播的發展,直播彈幕也逐漸火爆起來。在架構設計上,高穩定、高可用、低延遲是一款直播彈幕系統必備的三要素。bilibili網站架構師劉丁,從這三個方面出發,為大家帶來了 bilibili 在直播彈幕服務架構上的最佳實踐。
高併發實時彈幕是一種互動的體驗。對於互動來說,考慮最多的地方就是:高穩定性、高可用性以及低延遲這三個方面。
- 高穩定性,為了保證互動的實時性,所以要求連線狀態穩定。
- 高可用性,相當於提供一種備用方案,比如,互動時如果一臺機器掛了,此時必須保證可以和另外一臺機器連線,這樣就從側面解決了使用者連線不中斷的問題。
- 對於低延遲,彈幕的延遲週期控制在 1 秒以內,響應是比較快的,所以可以滿足互動的需求。
B 站直播彈幕服務架構(下面簡稱 GOIM )的出現就是為了解決這一系列的需求。下面將對此進行詳細的介紹。
B 站直播彈幕服務架構 GOIM 的出現
圖 1
直播聊天系統本質上也是一種推送系統,所謂推送系統就是,當你傳送一條訊息時,它可以將這個訊息推送給所有人。對於直播彈幕來說,使用者在不斷地傳送訊息,不斷地進行廣播,當一個房間裡面有 10 萬人時,一個訊息就要發出 10 萬次請求。在 GOIM 出現之前,也用過另一個名為 Gopush 的專案,這個專案推出的目的就是進行推送。在此之後,基於一些針對性的應用場景,GOIM 對 Gopush 進行了優化,從而出現在我們視野當中。GOIM 主要包含以下幾個模組(圖 1):
- Client
客戶端。與 Comet 建立連結。
- Comet
維護客戶端長連結。在上面可以規定一些業務需求,比如可以規定使用者傳送的資訊的內容、輸送使用者資訊等。Comet 提供並維持服務端與客戶端之間的連結,這裡保證連結可用性的方法主要是傳送連結協議(如 Socket 等)。
- Logic
對訊息進行邏輯處理。使用者建立連線之後會將訊息轉發給 Logic ,在 Logic 上可以進行賬號驗證。當然,類似於 IP 過濾以及黑名單設定此類的操作也可以經由 Logic 進行。
- Router
儲存訊息。Comet 將資訊傳送給 Logic 之後,Logic 會對所收到的資訊進行儲存,採用 register session 的方式在 Router 上進行儲存。Router 裡面會收錄使用者的註冊資訊,這樣就可以知道使用者是與哪個機器建立的連線。
- Kafka(第三方服務)
訊息佇列系統。Kafka 是一個分散式的基於釋出/訂閱的訊息系統,它是支援水平擴充套件的。每條釋出到 Kafka 叢集的訊息都會打上一個名為 Topic(邏輯上可以被認為是一個 queue)的類別,起到訊息分散式分發的作用。
- Jop
訊息分發。可以起多個 Jop 模組放到不同的機器上進行覆蓋,將訊息收錄之後,分發到所有的 Comet 上,之後再由 Comet 轉發出去。
以上就是 GOIM 系統實現客戶端建立連結,並進行訊息轉發的一個具體過程。一開始這個結構並不完善,在程式碼層面也存在一些問題。鑑於這些問題,B 站提供了一些相關的優化操作。在高穩定性方面,提供了記憶體優化、模組優化以及網路優化,下面是對這些優化操作的介紹。
GOIM 系統的優化之路
- 記憶體優化
記憶體優化主要分為以下 3 個方面:
1、一個訊息一定只有一塊記憶體
使用 Job 聚合訊息,Comet 指標引用。
2、一個使用者的記憶體儘量放到棧上
記憶體建立在對應的使用者 Goroutine(Go 程)中。
3、記憶體由自己控制
主要是針對 Comet 模組所做的優化,可以檢視模組中各個分配記憶體的地方,使用記憶體池。
- 模組優化
模組優化也分為以下 3 方面:
1、訊息分發一定是並行的並且互不干擾
要保證到每一個 Comet 的通訊通道必須是相互獨立的,保證訊息分發必須是完全並列的,並且彼此之間互不干擾。
2、併發數一定是可以進行控制的
每個需要非同步處理開啟的 Goroutine(Go 協程)都必須預先建立好固定的個數,如果不提前進行控制,那麼 Goroutine 就隨時存在爆發的可能。
3、全域性鎖一定是被打散的
Socket 連結池管理、使用者線上資料管理都是多把鎖;打散的個數通常取決於 CPU,往往需要考慮 CPU 切換時造成的負擔,並非是越多越好。
模組優化的三個方面,主要考慮的問題就是,分散式系統中會出現的單點問題,即當一個使用者在建立連結後,如果出現故障,其餘使用者建立的連結不能被影響。
測試是實踐過程中最不可缺少的一部分,同時,測試的資料也是用來進行參考比照的最好工具。
圖 2
圖 2 是 15 年末的壓測資料。當時使用了兩臺物理機,平均每臺的線上量是 25 萬,每個直播每秒的推送數量控制在 20-50 條內。一般對於一個螢幕來說,40 條就可以滿足直播的需求,當時用來進行模擬的推送量是 50 條/秒(峰值),推送到達數是 2440 萬/秒。這次的資料顯示,CPU 的負載是剛好滿,記憶體使用量在 4G 左右,流量約為 3G。從這個資料得出的結論是,真正的瓶頸負載在 CPU 上。所以,目的很明確,就是將 CPU 負載打滿(但是不能超負載)。
圖 3
2015 年之後,再次進行優化,將所有記憶體(堆上的、不可控的)都遷移到棧上,當時只採用了一臺物理機,上面承載了 100 萬的線上數量。優化效果體現在 2016 年 3 月的壓測資料(圖 3)中,這個資料也是最初直播時,想要測試的一個壓縮狀況。
從圖 3 的資料可以看出,優化效果是成倍增加的。當時的目的也是將 CPU 打滿,可是在實際直播環境中,需要考慮的最本質的問題其實是在流量上,包括彈幕字數,贈送禮物的數量。如果彈幕需要加上一些特殊的需求(字型、使用者等級等),贈送禮物數量過多這樣,都會產生很多流量。所以,直播彈幕優化的最終瓶頸只有流量。
2016 年之前,B 站的優化重點都放在了系統的優化上,包括優化記憶體,降低 CPU 的使用率,可是優化的效果並不顯著,一臺機器的瓶頸永遠是流量。在 2016 年 3 月份後,B 站將優化重點轉移到了網路優化上。下面就是 B 站網路優化的一些措施。
- 網路優化
最初 B 站的工作內容,主要是以開發為主,為了在結構上面得到擴充套件,所做的工作就是將程式碼儘量完善。但是在實際業務當中,也會遇見更多運維方面的問題,所以,在之後的關注重點上,B 站添加了對運維的重點關注。
圖 4
圖 4 是 B 站早期的部署結構。最開始,整套服務是部署在一個 IDC 上面的(單點 IDC),時間一長,這樣的部署結構也逐漸顯現出它的缺陷:
- 單線 IDC 流量不足
- 單點問題
- 接入率低
這樣的網路部署往往會造成延遲高、網速卡頓等問題。
針對以上三點問題,B 站也對部署結構進行了改善,圖 5 是改善過的網路部署結構,下面將對這個部署結構進行詳細說明。
圖 5
針對單點 IDC 流量不足的問題,B 站採用了多點 IDC 接入的方案。一個機房的流量不夠,那麼就把它分散到不同的機房,看看效果如何。
對於多點 IDC 接入來說,專線的成本是非常高昂的,對於創業公司來說,是一塊很大的負擔,所以可以通過一些研發或者是架構的方式來解決多 IDC 的問題 。針對多 IDC 的問題,需要優化的方面還有很多,下面列舉出一些 B 站現有的一些優化方案:
1、調節使用者最優接入節點
使用 Svrlist 模組(圖 6.1)支援,選取距離使用者最近的最穩定的節點,調控 IP 段,然後進行接入。
圖 6.1
2、IDC 的服務質量監控:掉線率
判斷一個節點是否穩定,需要不斷收集大量的使用者連結資訊,此時就可以使用監控來查詢掉線率,然後不斷調優,收集最終的結果去做一個拓撲圖(全國範圍),在拓撲圖當中就可以判斷出城市到機房之間的最優線路。
3、自動切走「失聯」伺服器
4、訊息 100%的到達率(仍在實現中)
對於彈幕來說,低丟包率是非常重要的。比如,訊息是價值上千塊的禮物,此時一旦丟失某些訊息,當用戶發禮物時,起到的效果就是,實際在彈幕中顯示出來的效果是,禮物數遠遠少於使用者花費金錢買來的禮物數。這是一個很嚴重的問題。
5、流量控制
對於彈幕來說,當用戶量到達一定級別時,需要考慮的問題還是流量控制,這也是對於花銷成本的控制,當買的機房的頻寬,是以千兆頻寬為計費標準時,當有超標時,一定要將超標部分的流量切走,以此實現了流量控制的功能。
引入多點 IDC 接入之後,電信的使用者依舊可以走電信的線路,但是可以將模組在其他機房進行部署,讓移動的一些使用者可以連線移動的機房。這樣就保證了,不同地區不同運營商之間,最優網路選取的問題。
可是解決了最優網路的選取,卻帶來了跨域傳輸的問題。比如在資料收集時,Comet 模組將資料反饋到 Logic,Logic 進行訊息分發時,資料便會跨機房傳輸。有些公司的機房是通過專線進行傳輸,這樣成本將會非常高。所以,為了節約成本就只能走公網的流量,但是公網的穩定性是否高、是否高可用,都是需要考慮的。當流量從電信的機房出去之後,經過電信的交換機,轉到聯通的交換機,然後到達聯通的機房,就會存在跨運營商傳輸的問題,比如丟包率高,因此,跨運營商傳輸帶來的問題還是非常嚴重的。
為了解決這個可能存在的風險,可以嘗試在聯通機房接入一條電信的線路(頻寬可以小一點),「看管」電信的模組,讓來自不同運營商的流量,可以走自己的線路。做了這樣的嘗試之後,不僅降低了丟包率,還滿足了對穩定性的基本要求,並且成本消耗也不高。可是,這樣的方案也不能說是百分百的完美,因為就算是同運營商之間的通訊,也會存在城市和城市之間某個交換機出現故障的情況,對於這樣的情況,B 站採取的方法是同時在 IDC-1 與 IDC-2(圖 5)之間部署兩條電信線路,做了這樣的備份方案之後,通暢程度以及穩定性都有非常明顯的提升。
針對上述過程中出現的一些問題,前期,需要對每個線路的穩定性進行測試。為了測試每一條線路的穩定性,可以把 Comet 放入各個機房中,並將 Comet 之間的通訊方式彙總成一個連結池(連結池裡可以放多個運營商的多條線路),作為網路連結可以將它配置成多條線路,用模組檢測所有的 Comet 之間的通訊,以及任何線路傳輸的穩定性,如果說通暢的話,則保證這個連結是可以用的。(這裡面有很多線路,所以一定會選擇通暢的那條線路進行傳輸,這樣,就可以判斷哪條線路是通暢的。)這樣一來,流量進行傳輸時,就有多條線路可以進行選擇,三個運營商中,總有一個是可以服務的。
綜合這些問題,B 站又對結構進行了重新優化。(這個結構剛剛做完,目前還沒有上線,還需要經過一些測試。)
圖 6.2
首先是 Comet 的連結,之前採用的是 CDN、智慧 DNS 。但實際上,有些運營商基站會快取路由表,所以即便將機器遷移走,部分使用者也並不能同時遷移走。而 DNS 解析這一塊,也並非完全可靠,而且一旦遇上問題,解決的流程又很長,這樣下來,體驗效果是十分糟糕的。其次是 List ,將其部署在一箇中心機房,客戶端採用的是 WEB 介面的服務,讓客戶端訪問這個服務,就可以知道該與哪些伺服器進行連線。將 IP List(Comet)部署在多個機房,可以將多個機房收集的值反饋給客戶端(比如:哪些線路通暢)讓客戶端自己選擇與那個機器進行連線。
如圖 6.2 。圖中將 IP 段進行了城市的劃分,將某一個城市的一些使用者資訊連結到一個群組(GroupID),群組下有一個或多個 Comet ,把屬於這個群組的物理機全部分給 Comet 。
圖 7
圖 7 是再次優化的結構,還是將 Comet 全部放在 IDC 機房中,訊息的傳輸不再使用 push(推)的方式,而是通過 pull(拉)的方式,將資料拉到中心機房(源站),做一些線上處理之後,再統一由源站進行資料推送。當然,這裡要十分注意中心機房的選取,中心機房的穩定性是十分重要的。除此之外,B 站在部署的時候還優化了故障監控這塊功能,用來保證高可用的服務。故障監控主要為以下幾項:
- 模擬 Client ,監控訊息到達的速率
- 線上開啟 Ppof ,隨時抓圖分析程序(CPU)狀況
- 白名單:指定人列印服務端日誌
設定白名單,記錄日誌資訊,收集問題反饋
標註重點問題,及時解決
防止訊息重現 - 伺服器負載監控,簡訊報警
低成本、高效率一直是 B 站所追求的標準,B 站將對 GOIM 系統進行持續優化和改進,以給使用者最好的直播彈幕體驗。
- RP原型資源分享-購物類App
- 實現各種效果和功能的按鈕,讀這篇文章就夠了
- 5分鐘的時間製作一個反彈球遊戲
- 35歲危機?內捲成程式設計師代名詞了…
- 線上文字實體抽取能力,助力應用解析海量文字資料
- 不買排名,不去SEO,如何做到登上谷歌搜尋首頁?
- HtmlParse:一款超輕量級的HTML檔案解析和爬取工具
- 五款當下超火熱的相親交友APP測評
- 盡一份孝心,為家人做一個老人防摔報警系統
- 作為軟體工程師,給年輕時的自己的建議(下)
- 技術分享| 淺談排程平臺設計
- 組態介面推陳出新:打造新一代再生水廠工藝二維組態系統
- 平頭哥 芯事訪談 | 全志科技CTO丁然:影片、AI市場爆發,RISC-V生態需要產業一起努力
- IDEA SSM Maven實現商品管理系統(超詳細SSM整合專案)
- 如何為迴歸測試選擇測試用例?
- 前端必學——函數語言程式設計(五)
- 40篇學完C語言——(第八篇)【指標陣列以及指向指標的指標】
- 焱融看|非結構化資料場景下,資料湖到底有多香?
- 低程式碼開發的未來~
- Docker容器:將帶UI的程式直接轉為Web應用,so easy