詳談[七牛直播雲]效能優化實踐
何李石,七牛雲首席佈道師、七牛雲早期工程師、技術專家。《 Go 語言程式設計》譯者。5 年以上網際網路從業/創業經驗,網際網路產品基礎架構解決方案專家。熱愛技術,專注於服務端分散式系統開發,為開發者和網際網路產品企業打造更好的企業雲服務產品。以下是他在七牛直播雲服務各個環節效能監控和優化的實踐。
一、七牛直播雲
1.業務模型
七牛直播雲是一個完整的解決方案,它包括推流端、網路和播放端三個部分。
圖 1
圖 1 為七牛直播雲業務模型。左下角是推流端;中間是實時流網路,可以理解為 CDN,但其網路架構與 CDN 不同;右上角是播放客戶端。
經常看直播的朋友接觸最多的是右上角的播放端;中間為實時流網路,紫色部分代表網路節點,節點之間的線路代表直播流的流向;左上角黃色部分為排程中心,異地雙活的排程中心儲存了當前網路的所有節點狀態,並能實時控制推流資料的走向。中間紅色節點表示當前故障節點,從圖 1 可看出,經過故障節點的路是不通的。這樣就構成了直播解決方案的基本業務模型,它涵蓋推流端推流,分發網路以及播放端等完整的環節。
本次分享的內容主要和效能相關,而直播的效能實際上涉及整個鏈路,包括推流端的效能、網路端效能以及播放端效能三個部分。
2.產品核心
圖 2
圖 2 為七牛直播雲的產品核心。它提供了三個端的 SDK:推流 SDK、服務端 SDK、播放端 SDK。其中,推流 SDK 控制視訊流的採集、處理和編碼,服務端 SDK 主要負責流的推流、傳輸和播放控制,播放端 SDK 負責視訊流的解碼和播放。
3.產品架構
圖 3
圖 3 為七牛的產品架構示意圖。七牛雲以儲存起家,有一個非常成熟的物件儲存系統。後來,為了滿足客戶快速上傳、下載檔案的需求,基於儲存搭建了靜態內容分發網路,即 CDN。然後,為了滿足客戶對靜態檔案的計算需求,搭建了基於物件儲存的資料處理平臺,甚至是更為通用的資料處理平臺,在這個平臺上使用者不僅可以部署基於物件儲存的計算任務,還可以部署完整的 Web 後端服務。
直播實際上是一個解決方案,它包含推流端 SDK,播放端 SDK,以及直播雲的 API。直播雲 API 在雲端會對直播流進行處理。我們知道,直播是一個分發通道,它包含兩個層面的含義,一:作為純粹的分發通道,二:對分發通道上的內容進行處理。其中內容處理包括:錄製回放點播、轉碼及內容處理、統計報表、內容識別、推流及播放加速。內容識別中最常見的是視訊鑑黃。而推流和播放加速是這個通道的主要功能。另外,基於直播雲解決方案,我們還需要開發一些運營相關功能,比如開發分割槽域甚至是更細粒度的報表系統等,以實時檢視當前所有使用者的推流資料。
4.使用正規化 圖 4
圖 4 是使用七牛直播雲的使用者或者直播類 App 開發者的使用正規化示意圖。開發者需要有一個 App Server,配合我們提供的推流 SDK、直播雲 SDK 以及播放端 SDK。App 中除了 Server 端和 DB 外,可能還需要實現一些業務相關的東西,比如彈幕、道具、點贊、聊天等功能。目前七牛沒有提供實現這類功能的基礎服務,但是作為一個開放的平臺,我們引入了一些提供 IM 服務的合作伙伴,可以基於 IM 服務和簡單的 App 業務開發實現這類功能。
二、需求和挑戰
在正式討論直播的效能優化之前,我們先來看看對於一個直播產品來說,它的關鍵效能指標有哪些?作為一個服務多個重量級直播 App 的直播基礎服務平臺,我們面臨著哪些挑戰?
1.直播關鍵效能指標
•首開時間。以映客為例,在視訊列表中隨意點開某個視訊,它的開啟時間最好控制在 1 秒內。
•累計延遲。視訊觀看與事件實際發生時間相距不能超過 3 秒,最好控制在1 秒內。
•卡頓。在不同的位元速率和解析度情況下,都能夠做到讓使用者流暢地觀看視訊。
•高可用。節點和線路是足夠冗餘的,並且不會有太大浪費;當節點或者線路出現故障時,可以通過快速的切換來恢復,這樣不影響終端使用者的體驗。
•低成本。對於創業公司來說,成本的控制非常重要。七牛作為一家創業型公司,我們一直在追求以技術的方式做到同樣高可靠、高可用、高效能以及體驗速度領先的情況下儘可能的節省成本。
2.挑戰
實時傳輸。對於直播而言,實時性非常重要,其中的優化主要體現在傳輸協議、網路節點以及鏈路方面。 海量終端使用者。當某個節點瞬間湧入大量使用者時,會出現驚群效應,它可能導致節點內所有使用者發生擁堵現象。 儲存。直播是一種時效性非常強的內容載體,當前直播的內容過期不候。相比點播視訊,它最大的缺點在於要求所有觀眾在同一時間在場,因此錄製儲存對於部分長尾使用者來說非常重要。另一方面,我們知道,出於監管的目的,國家要求必須將直播的內容錄製儲存下來,並儲存一定的時間。這樣就構成了直播對於海量儲存的強需求。 多屏終端。隨著移動網際網路的發展,市場上出現了越來越多不同尺寸不同種類的手機。為了滿足不同螢幕尺寸和硬體裝置的播放需求,服務端需要將原始視訊轉碼成多種不同格式和尺寸的可播放視訊。
三、直播推流端
1.推流效能優化
圖 5
如圖 5 所示,視訊流輸出前,需經歷採集、處理、編碼三個環節。為了每個環節做到最優控制,這一過程中需要設立一系列的 Buffer。
*採集環節:取樣率控制。這個環節中我們主要控制音視訊的取樣率,通過後一個環節中 CPU 的處理能力,實時調整採集原始視訊的清晰度和聲音質量的高低。 *處理環節:這個環節包括濾鏡、美顏、水印等處理功能,一般使用 GPU 對視訊進行處理。處理和編碼之間的 Buffer 主要用於控制編碼效率和編碼位元速率。 *編碼環節:編碼在推出前,會經過一個控制推流效率的 Buffer 區。這樣,客戶端和服務端配合,收到服務端的實時反饋後便可以實時調整推流位元速率。大家知道,客戶端劫持在中國是非常嚴重的現象,而即使沒有劫持,我們的解析也有可能失敗。這些情況下,就需要配合服務端,在網路方面做一些智慧排程策略。比如,在弱網環境中,我們可能會採取丟幀措施進行推流,從而優化推流效率。 除了這些緩衝區帶來的優化,推流端更大的優化在於視訊處理和編碼演算法,採用 GPU 代替 CPU 進行計算是較好的優化之一。而基於 H.265 標準的編碼演算法則能帶來比 H.264 更好的效能結果。當然,其中每一個話題都是領域相關的深水區,具體內容這裡不再展開,可以參考七牛雲公眾號上面關於編碼效能優化的文章。
2.推流端效能監測
除了與編碼相關環節處理優化外,質量實時上報模組(QoS )也是非常重要的一環。目前,七牛將自己與第三方的模組相組合,以 SDK 的形式提供給客戶,其中 QoS 模組作為可選模組,可以選擇性開啟。當終端使用者使用帶有我們 SDK 的直播 App 時,如果開啟了 QoS 模組,我們可以對終端使用者連線的節點進行實時監控,瞭解其推流失敗次數、卡頓次數以及卡頓時長。通過推流效能的實時監控和服務端實時排程系統的結合,可以實現對推流使用者線路和節點的實時調整。
另外,離線資料是一個非常重要的資料。僅看實時資料時,我們只能調整當前某個主播的推流調優。而對於整個網路而言,CDN 或者推流實時網路是一個不斷演化的過程,因此我們需要通過一些彙總的資料來判斷服務質量的好壞,例如,直播的總體卡頓次數,卡頓時長、卡頓率、平均推流時長、以及歷史可用性等指標。對於這些指標,我們與聽雲這類第三方 APM 服務提供商合作,通過第三方服務來收集和分析。
除實時 QoS 模組和離線資料收集模組外,我們還提供了一個可選的 App 報障模組,用於錯誤資料的收集。App 出現 crush 後,我們可以將這些錯誤資料通過「App -> SDK -> 服務端-> 分析報告」這樣一個路徑,排查 crush 的原因,通過真實使用者的反饋逐步改善 SDK 和 App 的穩定性。
四、直播服務端
1.實時流網路優化 圖 6
如圖 6 所示,紫色表示收流節點,收流後通過一系列線路將流轉發到另外一個節點。圖 7 中所有節點都對等,節點選擇遵循最優和就近原則。與傳統 CDN 節點分層的網路架構不同,圖中每個節點都可以進行收流、分流、轉發,或者對流進行處理。圖中假設,線路 A 經過的中間節點(紅色)出現故障,那麼排程中心會重新選擇一條線路 (線路 C)進行傳輸。也可以使用線路 B 進行傳輸,只是線路 B 和線路 C 的傳輸路徑較長,不符合最優和就近原則。
*去中心化網路 我們現在有很多海外使用者,其中有些從事跨境電商購物,因此對海外節點的需求比較強。對於一個去中心化網路架構來說,直接在日本或者新加坡部署一個節點非常方便,推流到使用者所在地區,然後走專線拉到國內的實時流網路節點進行分發和播放。因此,它的全球覆蓋面能夠快速構建 PoP ( Point of Presence )節點 。另外,通過邊緣節點快取分流,能夠很好抵抗驚群效應。這樣,就能做到快速擴容縮容,即讓該節點快速上線下線,不需要很大的快取區,構建一個低成本而高效的流傳輸網路。
*節點無狀態化 無狀態化非常重要。實時流網路中的節點只負責處理無狀態的事情。比如,收流後,對收到的流進行分發,當這個節點失靈,我們可以選擇一個臨近的節點和旁路進行分發,不需要關心原來節點上儲存的狀態。
*智慧排程 為了保證整個網路中的節點和線路可以隨時被替換,整個網路需要有一個多活排程中心,實時收集和探測節點與線路的狀態,通過排程和監控中心做每 5 秒一次的探活、節點之間的連通性以及頻寬的測試,保持傳輸網路和處理節點始終靈活高效。
*監測(排程中心) 監測是非常重要的一環。當流推過來,它每經過一個節點,我們都會統計其增率 FPS。一般來說,推流過程中流的位元速率不會發生太大變化,但是其幀率的細微變動很可能對終端使用者產生很大影響。瞭解實時增率,可以幫助我們監控整個鏈路質量。譬如,當北京聯通的客戶發生卡頓現象,我們可以知道他連線的邊緣節點是哪個,流從哪來,以及它經過每個節點時的 FPS 是多少,從而快速定位問題。另外,通過彙總資料,我們可以判斷當前選擇的節點的網路質量和處理能力,並結合歷史資料快速調整選點。
2.直播協議優化
圖 7
討論了網路後,服務端還有一塊重要內容,即傳輸協議。目前常用的三個傳輸協議包括:RTMP、HLS、HTTP-FLV。RTMP 延遲能控制在 1 到 3 秒;HLS 延遲可能會超過 10 秒,但是目前我們做到將其延遲控制在 6 到 7 秒;HTTP-FLV,顧名思義,是基於 HTTP 協議,只不過是基於長連線的 HTTP,延遲可以控制在 1 到 3 秒。
圖 8
圖 8 我們重點對比了 RTMP、HTTP-FLV 與 HLS協議的優缺點。如果我們更看重實時性,一般會選擇 RTMP 或者 HTTP-FLV,因為它們能滿足場景中較高的互動性需求。如果對跨平臺有較高要求,則 HLS 是更好的選擇。因為 RTMP 或者 HTTP-FLV 需要有一些特殊的支援,比如 Flash 播放器的支援,所以很難做成通用跨平臺的。而 HLS 則相對比較通用,它基於 HTTP,資料分發基於傳統 CDN,是將一個檔案切成小片,之後不斷更新其索引檔案。因此,它的優點是對已有CDN 相容性非常好,可以直接使用已有的 CDN 網路,缺陷是單向廣播,互動性比較低,這樣也導致了其延遲相對較大。
3.定製傳輸協議
除了剛才提及的協議,我們還可以使用定製的協議進行傳輸。RTMP 是基於 TCP 的 ,而 TCP 的傳輸控制會帶來一些額外的延遲。如果我們可以基於不需要做傳輸控制的 UDP 協議,進行直播流的傳輸,再加上比 TCP 更簡化的傳輸控制,就可以實現更低延遲。實測資料,延遲最低可到達只有 500 毫秒。
但是,七牛為什麼沒有選擇去定製協議?
對於雲服務提供商來說,第一,自己定製的協議不夠健壯,假如上生產環境後產生問題,則需要我們和客戶一起揹債,不斷填坑。而 TCP 或者 UDP 已經經歷了幾十年的考驗。
第二,現在的網路分發,無論是使用自建節點,或者第三方節點,都是基於 HTTP 或者 RTMP 協議的。當你的使用者量不大時,你可以自己定製協議,但當你的使用者量大起來之後,使用自己的定製協議則非常危險。拿 Facebook 來說,他們本來也可以嘗試定製協議,但目前來看他們依然使用 RTMP 這類古老的協議,因為它足夠健壯,並且在所有 CDN 廠商中足夠通用,相容性足夠好。實際上,無論是基於UDP 進行定製還是基於 P2P 進行傳輸,都是可行的。但是,作為一家需要對所有客戶都負責的基礎服務公司,我們現在還不太適合使用通用性不夠強的定製協議,這等於綁架使用者。
4.轉碼優化
圖 9
轉碼優化是服務端另一個重要環節。圖 9 中每個節點都是對等的,從收到資料流到分發至下一個節點,過程中的每個節點都可以進行轉碼。其中,我們標記了兩類轉碼節點,即收流時轉碼節點和播流時轉碼節點。為什麼會有這兩種區分?為什麼這兩種都可行?
一般來說,RTMP 原始位元速率不會小於末端位元速率,因此使用 RTMP 傳輸時,如果在收流節點進行轉碼,那麼內部轉發環節只需轉發低位元速率的目標碼流即可,這樣可以降低內部整體轉發頻寬。如果基於 HLS 進行傳輸,則可以在靠近播流端的邊緣節點中進行轉碼。因為 HLS 傳輸是基於HTTP 協議的,如果在收流端進行轉碼,則結果 ts 片段在內部轉發的效率太低,並且容易出錯。因此,建議使用 RTMP 協議傳輸,到達靠近播放端的邊緣節點後再進行轉碼。
那麼,如何做到每個節點都可以進行轉碼?我們前面說過,每個分發節點都是無狀態的,而轉碼也只是對檔案進行處理的過程,因此,節點不需要維持狀態,轉碼結束後,將流分發到下一個節點即可。實際上,目前一些新酷技術已經做到每個節點都可以轉碼。比如基於 Docker 的容器虛擬化,當容器中已經存入轉碼程式,那麼我們將自己的程式放入容器後可直接啟動轉碼程式。實際上,我們是在節點中部署了一個虛擬化的計算平臺,可秒級啟動其中的程式。如果該節點資源不夠,則可以將轉碼程式非常便捷的排程到其它節點進行處理。
另外,我們需要將流進行儲存,有時是為了回看,有時是因為監管需求。比如,在教育直播中,為了滿足觀眾回看的需求,需要把一些精品講師的視訊內容儲存下來,我們可以在靠近儲存的機房進行轉碼,而對於社交等其他場景,我們可以根據播放裝置的尺寸和硬體條件需要進行轉碼。
以上,是我們對實時流網路基礎結構、傳輸協議以及轉碼基礎架構和流程等優化的介紹,基本覆蓋了服務端優化的所有環節,這樣就構成了一個對流的傳輸和處理都比較高效的環節,同時能夠最大化網路和伺服器資源的利用率。
五、播放端
1.播放效能優化
播放端是離使用者最近的一端,即我們常談的最後一公里。播放端的效能主要關注三個點:首開延遲優化、累計延遲消除優化以及卡頓率優化。
1)首開延遲優化
要做到首開延遲,我們通常會在服務端快取一個 GOP,並且讓它的第一幀儘量是 I 幀,這樣客戶端播放器配合拿到第一個 GOP 資料後即可立即解碼播放,不需要等待。根據我們 Flash 播放器的實驗,目前這個延遲資料最低可以到 0.5 秒。
2)累計延遲消除優化:網路抖動
播放控制需要通過快取來消除累計延遲。對於首開延遲來說,快取越小越好,即拿到資料最好可以直接播放。但是,使用者的網路可能不太穩定,比如從 WIFI 環境切換到 3G 或 4G 網路環境時,網路會產生抖動。因此,為了消除網路抖動帶來的影響,我們需要在播放器端做一系列 Buffer,儘管 Buffer 會影響首開時間,但存在必要性,因此如何去平衡是優化的關鍵。
此外,視訊資訊中的 B 幀和 P 幀都是參考幀,它們沒有包含視訊的全量資訊,在解碼播放的時候它們都需要參考關鍵幀中的全量資訊進行解碼。B 幀是壓縮效率最高的資料幀,但它解碼時需要同時參考前後的 I 幀,即從拿到資料到正常播放需要等數幀時間,會帶來較大延遲。因此,除非網路或者解碼效能非常好,否則可以採取直接去掉 B 幀,以加快解碼,降低整體的延遲。
3)卡頓率優化
產生卡頓感的原因有多種,主要包括由於頻寬不足和 I 幀不足帶來的卡頓感。其中,頻寬不足在推流端、傳輸端和播放端都可能發生,推流端的頻寬不足導致推流 FPS 下降,導致整體使用者推流和播放卡頓,傳輸端頻寬不足導致所有播放使用者卡頓,播放端頻寬不足導致當前觀看使用者卡頓。而 I 幀不足即 GOP 太大,則會導致解碼播放過程中所需關鍵幀到達的速度跟不上播放器解碼和播放速度。
因此,卡頓的優化是整個環節的優化過程,只有七牛直播雲這樣提供覆蓋多個端的解決方案才能進行徹底排查優化,而接下來要介紹的自適應播放只是卡頓優化的一部分內容。
2.HTTP 自適應播放流程
圖 10
那麼,如何基於 HTTP 實現位元速率自適應的播放呢?從圖 10,我們可以看出基於 HTTP 協議的快取分發方式,可以預先在服務端邊緣節點快取多份不同位元速率的資料,播放端可以根據當前網路質量和請求的效果,實時調整當前請求的位元速率,從而達到播放端自適應播放的效果。
3.自適應播放原理
圖 11
圖 11 是一個非常簡單的自適應播放模型,從圖中我們可以看到視訊播放器中自適應播放常用的三大模組,以及播放流程。播放流程如下:首先,服務端會將資料切成多個位元速率的視訊檔案並儲存下來。然後,播放端向服務端發出請求獲得 A 位元速率資料 ,服務端通過 HTTP 將 A 位元速率的資料傳到客戶端。客戶端除請求外,還扮演了更多角色,首先它有一個頻寬預估模組,即通過當前使用者的頻寬大小,及其可承受的視訊位元速率大小進行頻寬預估,後通過預估結果為使用者選擇相應的位元速率,並進行實時調整。選擇位元速率後,通過下載排程模組實時排程當前位元速率,然後通過 HTTP 介面到服務端拉取資料,再將資料拉到播放端進行播放。接著,根據當前播放效果進行資料反饋。比如,拉一個 ts 片斷所耗時長,通過計算平均拉取花費的時間,預估下一次拉取的資料大小。當然,圖 12 中演示的是基於 HTTP 的自適應播放原理,實際上該原理和協議無關,基於 TCP 協議的播放也可以做到。只是無狀態的 HTTP 更符合 CDN 分發的直覺,所以拿它來舉例。
4.播流效能監測
通過頻寬預估模組、位元速率選擇模組、下載片段排程等三大模組可以很好的控制視訊片斷的拉取,並通過實時反饋進行位元速率調整。
頻寬和播放運營資料的流向僅限於播放器內部。而實際上,在播放端,除了與播放相關的模組,與推流端類似的 QoS 模組也可以利用頻寬和播放運營資料。QoS 模組負責播放過程中對效能進行監控,當然我們也可以基於第三方模組對效能進行監控,比如,聽雲的監控調優和報警。而監控中我們主要關注什麼?
•首開時間。剛剛提到我們能做到首開時間 0.5 秒,其實它是平均值,有些可能是 0.1 秒,有些可能超過 1 秒,我們需要進行篩選,再進行。
•播放的失敗次數。到底是推流失敗導致視訊無法播放,還是因為使用者本身的網路導致播放失敗?假如使用者沒網,則這些資料無法上報。
•卡頓次數和卡頓時常。整個播放過程中卡頓了多少次?總計時常是多少?使用者播放過程中位元速率的切換是否頻繁?切換位元速率之後是否有效?
除了上述提及的實時資料之外,我們還需要評估離線的歷史資料,即通過彙總報告來綜合評估整個推流、播放、網路效果,以及終端使用者的網路分佈,而這些功能在一些第三方服務比如聽雲中已經非常完善了。 如果您對更細節的直播技術感興趣,歡迎閱讀《直播技術詳解》系列文章。
相關文章
- 效能優化,實踐淺談優化
- 手遊錄屏直播技術詳解 | 直播 SDK 效能優化實踐優化
- 直播分享| 騰訊雲 MongoDB 智慧診斷及效能優化實踐MongoDB優化
- 直播推流端弱網優化策略 | 直播 SDK 效能優化實踐優化
- 效能優化漫談之七:效能優化的誤區優化
- SOFARPC 效能優化實踐(上)| SOFAChannel#2 直播整理RPC優化
- SOFARPC 效能優化實踐(下)| SOFAChannel#3 直播整理RPC優化
- 七牛雲試用指南-單檔案直傳(實踐)
- gprof的效能優化實踐優化
- SAP ABAP 效能優化實踐優化
- 騰訊雲Elasticsearch叢集規劃及效能優化實踐Elasticsearch優化
- 「視訊直播技術詳解」系列之七:直播雲 SDK 效能測試模型模型
- 七牛雲OSSUtil
- TiDB 效能分析&效能調優&優化實踐大全TiDB優化
- ⚠️Flutter 效能優化實踐 總結⚠️Flutter優化
- Canvas 動畫的效能優化實踐Canvas動畫優化
- FlutterWeb效能優化探索與實踐FlutterWeb優化
- 前端效能優化原理與實踐前端優化
- Tree-Shaking效能優化實踐 - 實踐篇優化
- 如何實現高效運維?來談談效能優化那些事(含直播回顧 Q&A)運維優化
- golang七牛雲操作Golang
- php實現七牛雲相關操作PHP
- 讀小程式效能優優化實踐-筆記優化筆記
- Vue 專案效能優化 — 實踐指南Vue優化
- 基於 PageSpeed 的效能優化實踐優化
- HBase最佳實踐-讀效能優化策略優化
- hadoop JOB的效能優化實踐Hadoop優化
- 途牛旅遊系統架構的優化實踐架構優化
- Bitmap優化詳談優化
- 從 React render 談談效能優化React優化
- 【七牛雲】儲存實施工程師工程師
- 七牛雲 goc docker 部署GoDocker
- 七牛雲物件儲存物件
- 效能優化詳解優化
- ASP.NET Core 效能優化最佳實踐ASP.NET優化
- 前端感官效能的衡量和優化實踐前端優化
- TiDB 效能分析&效能調優&最佳化實踐大全TiDB
- 【效能優化實踐】優化打包策略提升頁面載入速度優化