乾貨:如何打造一個直播平臺
上幾篇介紹瞭如何實現一個百萬級別的語音聊天室,本篇將介紹直播平臺的設計。開始分享這個專案其實有點猶豫,因為我所參與的直播平臺跟業界常用的方案不太一樣。但是仔細想想,架構設計本來就是在各種條件約束下的因地制宜,沒有絕對的正確和錯誤,合適才是關鍵。
我們是國內做直播相對比較早的團隊,也缺乏一些行業通用方案的參考,因此很多地方是自己通過踩坑摸索出來的。因為最開始我們產品只支援語音聊天,後來隨著直播業務(娛樂直播、遊戲直播)的普及,才開始支援視訊直播,所以最樸素的想法就是,直接把語音服務的架構拿過來用。
上篇介紹了語音聊天室的完整架構,我們的設計就從這裡開始。視訊服務可以用這種架構嗎?答案是肯定的。把上圖中的語音資料替換成視訊資料就可以了,唯一的不同是語音聊天室多個使用者可以同時說話,但是直播平臺就只能有一個主播。
但是,隨著業務不斷增長,問題開始出現:一個SET內的房間數量到達了瓶頸。為什麼呢?這要從語音伺服器的實現說起。
如圖所示,每個語音伺服器為每個房間維護6個語音通道(採用迴圈佇列實現),其中5個通道分別快取5個使用者的語音資料,第6個是混音通道。沒錯,是5個使用者,聊天室的設計就是最多隻支援5個使用者同時說話,因為同時說話的人再多就會聽不清楚。那其他人想說話怎麼辦?一般的做法是聊天室的搶麥或者使用者多長時間不說話就自動放棄通道,或者像LOL這種遊戲團隊設計就只有5個人。混音通道實際上就是把5個通道的資料根據時間順序放到一起(當然還有一些其他處理),聽眾收到的是混音通道的資料。
視訊伺服器因為每個房間只有一個主播,因此只需要維護一個視訊資料通道,實現上與語音伺服器類似。按理說,視訊伺服器應該更簡單才對,但是卻有別的問題。
之前說過,語音伺服器是按照SET來部署的,一個SET包含多個語音伺服器,房間分佈在一個SET內的機器上。因此通常一個房間會分佈到多臺語音伺服器,這樣主要是為了使用者的就近接入。那SET內的房間數受什麼制約呢?
之前沒有介紹的一個細節是,下圖所示,如果一個房間分佈在多臺語音伺服器,這些語音伺服器上都需要維護這個房間的6個語音通道(為什麼不是隻維護混音通道,大家自己思考),因此房間數的制約主要在於單臺伺服器的記憶體大小。
因為語音資料是很小的,一個包大概300多位元組,6個語音通道佔用的記憶體大概幾M,一臺4G記憶體的機器就可以承載上千個房間。按照之前的計算一個SET 10臺機器可以承載20萬的使用者,上千個房間幾乎是不可能的,因此對於語音服務,記憶體的瓶頸是不存在的。
但是對於視訊服務就不一樣了,視訊資料可是很大的,一幀的資料有時候可以達到幾M, 1個數據通道都可能佔用幾十甚至上百M的記憶體。因此單伺服器可承載的房間數可能只有一百個,也就是說單SET的房間數最多隻能有一百個,這裡就是瓶頸所在。
大家注意了,這個瓶頸是無法通過平行擴充套件增加機器來解決的,因為每臺機器都受到這個限制(當然可以給每臺機器加記憶體來解決,但是這種做法一方面增加了成本,另一方面增加了故障的概率)。這是一個系統架構導致的問題,解決方法可能很多,例如摒棄分SET的架構,或者把SET機器數減少等等。可以說,這個問題把我們從最開始閉門造車的野路子拉回了業界的通用標準。
做過直播的同學應該對上面的圖都很熟悉,它是一個典型的直播平臺的架構圖。這個圖跟我們最開始的架構有一個最本質的區別是,我們採用了別人的CDN。為什麼要加“別人”?因為我們之前實際上是在嘗試做自己的CDN來實現資料的分發。但是這條路走下來是個無底洞,我們沒有別人的資源豐富和專業。因此,上面的架構中,我們只負責生產資料,我們維護主播上傳的視訊資料,並把視訊資源資訊上報給回源伺服器。使用者開啟直播時,先去CDN請求資料,如果CDN沒有資料,就會到回源伺服器查詢資源地址,並向資源所在的視訊伺服器請求資料返回使用者。下次使用者開啟視訊的時候,CDN就直接從自己維護的資料通道中獲取視訊了。
本篇主要介紹了視訊服務架構演進的過程,描述了從最開始照搬語音服務的架構,到面臨架構瓶頸時,轉而採用目前業界通用的架構的思路歷程。架構設計跟專案所處的時代背景和階段密切相關,每個階段都有其侷限性,不能因為技術發展而完全否定原來的設計思路,現在所謂的業界標準也是從一次次的踩坑中走出來