騰訊研發總監王輝:十億級視頻播放技術優化揭秘

urbn5787 7年前發布 | 39K 次閱讀 移動應用 騰訊 軟件架構 視頻播放

QQ 空間在 2016 年日均視頻播放量由年初的千萬級迅速突破到十億級,過程中也對整個視頻播放技術的可靠性、性能、操作體驗等方面提出嚴峻的考驗,相關質量急需提升。經過多個迭代持續和各項優化,外網整體質量已經達標:在保證播放成功率提升到 99.92% 的基礎上,首次緩沖耗時降到 0.70s,二次緩沖概率降到 0.48%,做到穩中有升。我們將從視頻組件的整體架構,優化效果衡量,首次緩沖耗時優化,播放成功率優化,二次緩沖優化,總結六個方面介紹視頻點播在整個優化過程中的心路歷程。

寫在前面

我今天的話題是“十億級視頻播放技術優化揭密”。介紹我們團隊在去年短視頻風口上,視頻播放量從 5000 萬到十億級過程中的一些技術實踐,希望我的分享能給大家帶來一些借鑒和參考。

自我介紹一下,我叫王輝,來自騰訊,從 2009 年開始從事 QQ 空間技術研發,近期主要關注手機短視頻、視頻直播、AI 智能硬件。我個人喜歡跑步,覺得跑步是解決程序員亞健康的一個比較好的方式。

眾所周知,短視頻去年是一個風口,起因是來自 非死book 2015 年 Q3 的財報,財報表明在 非死book 平臺上每天有 80 億次短視頻播放,給 非死book 帶來了強勁的廣告收入,正是這個數據給國內核心大公司和創業公司帶來的一些新的突破口。

其實短視頻已經不是一個新的概念,從 2006 年開始國內就有很多公司在做短視頻。隨著 非死book 吹起短視頻風,去年在短視頻行業有近百款應用出現,中國網民里面每 5 個里面就有 1 個是短視頻的用戶,短視頻成為互聯網的流量入口。

QQ 空間也在這個風口中,從 2015 年 11 月份的每天 5000 萬視頻播放量,經過一年的耕耘細作,徒增到 2016 年 12 月份的 10 億量級,現在還在不斷增長。

我的分享主要是按照我們產品迭代的幾個關鍵步驟展開:

1、首先是快速上線,2015 年我也是跟隨著大家的體驗快速上線了新短視頻的體驗;

2、其次面臨的是成本問題,在做的過程中做了一些成本的優化工作;

3、然后是體驗優化。在解決成本問題之后,短視頻的觀看體驗要做到極致。比如說視頻的秒開、不產生緩沖、不卡、成功率的提升。

快速上線

首先看快速上線,在開始之前,我先介紹一下我們的團隊職責,我們團隊負責手機 QQ 和手機 QQ 空間兩個 APP,每個 APP 有 iOS 和 Android 兩個團隊,一共四個團隊,四個團隊負責兩個 APP。在這個項目中,我們四個團隊要針對兩個平臺實現四套邏輯,這里的效率是存在一定的問題。

關于短視頻體驗,在這之前,我們也只是做到能播放而已,沒有做很精細的工作,并且這里的產品觀感體驗也不是很一致,也不是很好。

技術上,之前也只是做很基礎的架構,直接由播放器連接服務器下載數據,達到能播放就可以。之前我們沒有積極去做這個事情,導致播放成功率低、失敗原因未知、不支持邊下邊播、緩沖時間比較長等問題,流量浪費也比較嚴重。

在產品上要解決的,是在整個 APP 里面把所有產品的體驗做到一致,比如說每個功能的觀看體驗,視頻浮層的體驗,統一觀看體驗也為我們項目清除了很多障礙。

而這里的技術上的要點是非常關鍵的,第一個是邊下邊播,這是基礎的要求,是為了加快視頻播放速度。第二個是流量的控制,這么大的平臺,之前只是做 5000 萬的播放量,如果沒有流量控制的云策略,可能到后面流量是無法把控的。第三,剛才講到團隊的現狀,團隊要負責兩個 APP,這里要做代碼復用,不可能再像之前一樣四個團隊維護四套代碼,第四,我們支持第三方的視頻源。第五,需要完善監控上報,對業務知根知底。

可以看到,完成核心技術要點最核心的一點是如何控制視頻的下載,傳統的方式是播放器直接塞播放地址給播放器,它就可以直接播放,這其實是一個黑盒。我們在中間加了一個本地代理,播放器與服務器的數據請求,我們完全可以把控。在這個過程中,比如說播放器要數據時,可以給它更多的數據,這樣能解決它緩沖的問題。有了這層代理之后,架構也更清晰一點。

基于 MVC 架構,在 MODEL 一層做一些業務的邏輯,在 VideoController 這一層做控制視頻的播放和下載。有了下載代理之后,就可以通過代理管理下載,在 APP 里面有很多的視頻請求,VideoProxy 可以管理這些請求,做流量控制,做預加載,還可以做優先級調度和做監控上報,下載邏輯層則主要關注怎么優化服務器,對接緩存管理層,同時我們抽象出了一個數據層,我的數據源可以是 HTTPDataSource,也可以讀本地,也可以是來來自騰訊視頻的數據源,也可以是第三方 APP 的數據源,協議層主要是 HTTP、HTTPS、HTTP2 的解決。

在 VideoController 的邏輯里,其實都可以放到 C 層來實現,這樣安卓和 iOS 完全可以通用,這一層的邏輯可以在 QQ 和 QQ 空間兩個 APP 里面使用,相當于是我們一套邏輯可以完全復用,不用再開發四套邏輯。

我們團隊的職能也做了相應調整,之前可能是按團隊劃分,四個團隊負責四個終端,現在可能是按 FT 的方式劃分做視頻的團隊,iOS 做視頻的團隊可能負責 QQ 和 QQ 空間里的業務,安卓也是如此。直播的 FT 也可以這樣劃分,iOS 的負責 iOS 的兩個 APP,安卓的負責安卓的兩個 APP,這樣代碼復用更清晰一點,我的團隊更專注一點。視頻的團隊專注視頻的研發。

監控上報,肯定是不可缺少的,這是一個成熟的項目必備的要素:

1、問題定位,老板跟用戶反饋說我這個視頻播不了,要有一套成熟的問題定位的方式;

2、耗時統計,用戶播放這個視頻花多長時間播出來,這也是要了解到的;

3、成功率統計,外網用戶播放視頻的成功率是多少?還要通過實時報警,才能及時知道外網發生一些故障。

傳統的撈 Log 方式大家都有,但是這種方式效率太低,需要等用戶上線之后才能撈到 Log,Log 撈到之后還得花時間去分析。我們做法的是在關鍵問題上做一些插裝,把每一類錯誤和每一個具體的子錯誤都能定義出來,這樣一看錯誤碼就知道播放錯誤是由什么原因導致的。

還可以把每次播放視頻的鏈路所有關鍵流水上報到統計系統里來,每一次播放都是一組流水,每一條流水里面就包含了例如首次緩沖發生的 Seek,或下載的鏈接是多少,下載的時間是多少,有了這些流水之后,用戶反饋播放失敗,我首先可以用流水看發生了什么錯誤?錯誤在哪一步?每一步信息是什么?幾秒鐘就可以定位到問題。

有了這個數據上報之后,還可以做一些報表。比如說可以做錯誤碼的報表,有了報表之后就可以跟進哪個錯誤是在 TOP 的,負責人是誰,原因是什么,都可以看到。

我們也有自己實時的曲線,可以看到各項數據的情況。

在告警方面,基于成功率和失敗率的統計,進行實時告警。一出現錯誤碼,微信立即可以收到提醒,提醒說是什么原因導致這次告警,完全全自動。

成本優化

上線一個月之后,一個壞消息一個好消息。好消息是播放量漲了 4 倍,壞消息是帶寬漲了 6 倍,帶寬優化是每個做視頻的人必須要面臨的問題!

我們也分析這個過程中的原因,發現因為改為邊下邊播之后用戶觀看視頻的意愿比較強,用戶有挑選心理,不是每個視頻都去看,看了一下之后不喜歡就劃走了,之前下載的那部分其實是浪費的。

如果之前不做限速的話,一點開視頻就瘋狂地下數據,帶寬有多大就下多少的數據,這樣浪費很嚴重。我們采取的第一個策略是進行流量控制。在高峰期播放到第 10 秒時,預下載 N 秒數據,下載到 N 秒就停下來。然后,可以做多級限速。一開始不限速,下載到合適時機做 1 倍碼率限速。高峰期時預加載的數據會少一些,防止高峰期時帶寬占用明顯,這是初級的策略。最終我們也有碼率切換的策略。這對用戶的觀看體驗影響比較大,這也是之前必備的一個策略。

上線這個策略之后,對帶寬的優化還是比較明顯的。在高峰期時從 18:00 到凌晨 1 點帶寬下降 25.4%,這個是我們不斷灰度最終確定的值。這個值會影響播放緩沖,因為數據少的話必定會卡頓,在卡頓之間和流量之間取了一個最優值,最終是 25.4%。

但這樣肯定是不夠的,因為流量漲的還是很明顯的,我們想到 H.265,壓縮率相對于 H.264 提升了 30%-50%,但它的復雜度也是呈指數級上升。復雜度導致它的編解碼耗時更長,占用資源也更長。如果把 H.265 用在客戶端上的話,可能要評估一些點,比如說在編碼上面,現在手機上沒有做 H.265 硬件支持的,相對于 H.264 的耗時 3-7 倍,之前耗時可能是 10 分鐘,而現在可能需要到 70 分鐘左右。

解碼的硬件支持 H.265 的也很少,耗時差不多是一樣的。解碼是可行的,你可以采用軟解的方式,這個帶來的問題是 CPU 占用非常高,可能之前 H.264 占 20% 的 CPU,H.265 占 70%、80% 左右,帶來的問題是發熱和耗電。

結論,解碼是可行的,但是編碼不用考慮,在移動客戶端不可行的情況下,那編碼就要放在后臺來做了。

為了解決如何在我們手機上能夠解碼的問題,對手機的解碼能力做一次評估。我在合適的時機做一次大規模的浮點數運算,將數據上傳到后臺服務器進行云適配。如果當前的指數滿足 H.265 條件的話,可以給你下載 H.265 視頻給你播放。從而保證軟件解碼柔性可用,針對視頻源規格按機型適配降級,保證用戶視頻播放體驗。

經過評估之后,判斷當前機型更適合 360P 還是 480P 等等,保證如果手機不適合 H.265 就不會給你的手機下發 H.265 視頻的。

經過我們的統計,外網上有 94% 的手機還是支持 H.265 解碼的。支持 1080P 手機的解碼占 46%。

編碼只能在后臺做,如果在視頻后臺進行全面編碼的話,是不現實的。因為編碼復雜度呈指數級上升,拿后臺服務器進行編碼也是不可行的。我們的做法是只用熱點視頻進行后臺轉碼,不是所有視頻都去編碼,對觀看量在 TOP N 的視頻進行編碼,只需要編碼少量的視頻就可以帶來流量優化效果,因為 TOP N 就占了全網 80-90% 的流量,只對少量的視頻進行解碼,讓 90% 的視頻享受轉碼的優勢。

因為熱點轉瞬即逝,可能前一分鐘是熱點,后一分鐘就不是熱點,社交網絡的傳播非常快,我們給后臺的要求是轉碼速度一定要快。在之前沒有優化時,轉一個 10 分鐘的視頻要半個小時左右。后來做了分布式處理之后,轉 10 分鐘的視頻只用 2-3 分鐘。一些短視頻最長 5 分鐘左右,只要監測到視頻很熱的話,1 分鐘之內就能轉出來,就是 H.265 了。

同樣,在 H.265 編碼器上做了一些優化,比如編碼速度和碼率的節省都會有提升。

經過 H.265 嘗試之后,帶寬進一步下降,節省了 31% 左右。

帶寬問題解決之后,面臨的下一個問題是體驗優化。用戶最想要的是視頻能立馬播出來 。

我們定了一個秒開技術指標,只要這個視頻從到我的視野范圍,到視頻播出來之間的耗時在一秒以內。這也是對標 非死book 的體驗,非死book 一打開動態,視頻是能立即播出來的,不需要等待就能播,這個體驗其實很順暢。

核心的流程主要是三個步驟:

1、客戶端初始化播放器;

2、下載數據;

3、等待播放。

這里主要有兩個大的耗時點,第一下載視頻數據耗時;第二個是客戶端的耗時,下載視頻數據耗時的話,主要是下載數據量和下載的速度。

這里有一個很直接的問題,播放器需要下載多少數據才能播放?

我們可以看一下 MP4 格式,MP4 其實是一個比較靈活的容器格式,每個東西都是用 Box 表達的,每個 Box 又可以嵌入到另外一個 Box。MP4 主要由 MOOV 和 Mdata 組成,MOOV 是囊括了所有的視頻關鍵信息,肯定是先把 MOOV 下載完之后才能找視頻數據才能播起來。不巧的是,在我們外網會發現有 5% 左右用戶上傳的視頻,它的 MOOV 是在尾部的。后來也發現,有很多安卓手機比如說山寨機,一些攝像頭處理的廠商可能比較偷懶,因為他們只有在你采集完信息之后才能知道他所有的信息,他可能把所有的信息放在尾部。

對于 iOS 來說,一開始把頭部下載了,找不到 MOOV,就猜測 MOOV 在尾部,多一次 Range 請求去探測 MOOV 到底在哪?基本做法是去尾部探測, 如果 MOOV 在其他地方的話,這次播放肯定是失敗的。安卓某些手機如果沒有經過處理,MOOV 在尾部的情況下需要下載整個視頻才能開始播放。

我們的處理方式,用戶在后臺統一做一次轉碼修復,客戶端采集后做一次轉碼修復。

看一下 Mdata,視頻的原數據。目前大部分是 H.264 編碼,H.264 通過幀預測的方式進行視頻編碼。這里有一個 GOP 概念,也是在直播里面經常談的。一般的播放器需要下載完整的 GOP 數據才可以播。

需要下載多少數據才能播呢?每個播放器的行為也不一樣。iOS 要下載一個完整的 GOP 才可以播。像 FFmpeg Based Player 的話只需要關鍵幀就可以播出來。安卓是比較尷尬的一個系統,在 6.0 及以下,需要下載 5 秒視頻數據才可以播起來。

如果需要下載 5 秒數據才可以播的話,肯定是非常慢的。我們這里的策略會采用 FFmpeg Based Player 自己來做解碼,要關注兼容性和耗電的問題。解決了 Mdata 之后,如果 MOOV 數據在頭部,拿關鍵信息進行播放的話,其實需要的開始播放數據量是非常小的。

對于下載優化,會有一個防盜鏈的請求,通過 HTTP 拿到真實的播放 URL 才可以下載數據。

但是在手機上執行 HTTP 請求非常耗時,這里走私有長連接通道做這個事情。

關于優化下載鏈路,這里也是談的比較多的,一般也是直接輸出 IP 地址,利用 IP 地址做跑馬的策略,兼顧性能的效率,這個是用的比較多的方式。

進一步思考,按照普遍 600K 碼率的話,我們統計到現在 APP 上面下載的平均速度是 400K 左右,這樣計算的話,可能在安卓上面播放一個視頻的話,需要將近 0.9 秒左右才可以下載到你需要的數據。

如果碼率再進一步提升的話,可能會更大,這其實我們也做了一些場景分析,會發現我們是社交網站,它有好友動態,視頻在好友動態里播放,或者是在視頻浮層里播放,我們的選擇是預加載的策略,這也是常見的策略。

我們會在當前看這條動態時,預加載后面視頻的關鍵信息,比如會加載頭部信息和需要播放的數據。在播放當前視頻時,加載一定數據之后會加載下一個視頻的數據,這些都可以做到的。預加載有一個問題,我們之前踩了一個坑,可能預加載視頻時還是要優先圖片的。視頻當然重要,但是社交網絡的圖片更重要,可能在預加載視頻時會考慮到更高優先級的一些任務。

優化效果也是比較明顯,經過剛才幾個策略,一個是我們對頭和播放器的處理,我們對防盜鏈的處理,還有對下載鏈路的處理和預加載,這樣我們的耗時大幅度減少了,之前是 1.8 秒降到 0.6 秒左右。

客戶端的性能也是讓人容易忽視的問題,發現有些用戶雖然有視頻的緩存,但是播起來還是很慢,這其實是客戶端性能的影響。

因為視頻涉及到的流程比較多,在這個過程中還要更關注客戶端的影響,要分析下客戶端哪些在搶占視頻播放資源,我們之前犯過一些錯誤,md5 會卡住一些流程,或者是 HttpParser 會阻止你的任務,會導致視頻播放更慢。

在優化視頻播放過程中,我們在 4 月份也做直播。直播這里面插入個事情,我們要播放直播的視頻流,是 HLS 的視頻,在好友動態里面可以觀看直播的內容。HLS 在安卓上面體驗非常差,因為安卓 3.0 之后對 HLS 基本沒有做的優化工作,這里每次安卓上播放 HLS 需要等待 6-9 秒。

分析發現它的處理也不是很得當,因為安卓系統請求鏈路較長,串行下載,需要下載 3-4 片 TS 才能啟動播放,下載 3 個分片的話,耗時就會很久。之前提到我們這里有代理,有了代理之后做事情方便很多了,通過里獲取 M3U8,解析 M3U8 里面有哪些文件,可以做并行下載,只讓他下載一次 M3U8,這樣下載速度大幅度提升。回到剛才架構上,有了下載代理層的話,你可以做 HLS 的加速和管理,可以加入 HLS 的視頻源。

回到剛才架構上,有了下載代理層的話,可以做 HLS 的加速和下載管理,可以加入 HLS 的視頻源。

HLS 優化效果也是很明顯的,之前需要 6 秒左右,現在 1 秒左右就可以播起來。整體從之前的 2 秒左右,現在優化到 700m 秒,0-1 秒的占比目前在 80% 左右,80% 用戶都可以在 1 秒內播視頻。

體驗優化

還有一個是用戶比較關注的問題,觀看視頻時卡,觀看一會卡了一下,loading 數據,loading 完以后又卡,這個體驗非常差,我們希望所有的視頻都不卡。

其實這有兩個播放場景,一個是正常場景,邊下邊看,數據在下載。對于正常場景下載時會做一些帶寬調整,在低速時會做切換 IP 的處理,比如說當前連通 IP 的耗時比較久的話,會做一些處理,也會對網絡進行速度限制。

針對 Seek 場景,用戶拖動,如果文件緩存系統是順序存儲系統的話,必然會造成拖到這里時,后面的緩存數據沒有辦法下載到系統里面來。只要用戶每次拖動,拖動后的下載數據沒法存到硬盤上來。

我們就對存儲做了一次重構,支持文件空洞。會按照一兆的方式進行文件碎片劃分,這就是視頻的數據,每一兆就是個文件分片,通過它的 Key 和文件進行存儲,這樣好處是可以分段存儲,可以允許邏輯空洞,拖動的話也可以在后面存儲,也不依賴數據庫,通過文件名可以知道是從哪個位置到哪個位置的存儲。這樣淘汰緩存高效一點,可以制定更靈活的緩存策略。可以淘汰更低粒度的文件,比如 seek 之后的文件可以保留,還可以對文件加密。

產生卡頓的用戶里面,90% 是因為進行拖動,拖動之后又沒有緩存數據,所以這里有可能導致緩存。統計效果也是比較明顯的,上了分片緩存之后,之前的緩存概率是 4.6% 左右,最后下降到 0.48%,基本上看不到發生緩沖的場景。

成功率優化,也是比較關鍵的指標。成功率優化沒有捷徑,可能是 Case by Case 各個擊破。針對錯誤進行編碼,有幾百個錯誤碼,每一個錯誤碼撈 log 去看,錯誤碼原因進行上報,每次進行循環一個個錯誤碼進行解決。

DNS 劫持是比較多的,會劫持你的請求。這個是在國內比較常見的劫持,有的小運營商按 URL 劫持視頻內容,可能直接污染 DNS 讓你查找不到 CDN,這是比較多的,還有一些網絡不穩定的影響導致。更高級的直接污染視頻內容,讓視頻內容是錯誤的。

播放比較多的可能是一些編碼的原因,手機采集出來的視頻在低端手機上播不出來,我們會對這些視頻進行修復。

邏輯上的問題,因為播放器是有狀態機的,開發人員比較多,每個人過來加一個邏輯的話,會導致播放狀態出現問題。

我們解決播放器錯誤的方法:HOOK 播放器接口與回調,實現播放器狀態機,監控插放器 API 的調用是否合法,不合法直接告警或 Crash。幫助開發快速定位問題,同時減輕測試同事的負擔,封裝成 UI 組件,使其它開發不必理解播放器。

最終優化的成果是這樣的,下載成功率優化前是 97.1%,優化后是 99.9%。播放成功率優化前是 97.0%,優化后是 99.9%。首次緩沖耗時優化前是 1.95s,優化后是 0.7s。二次緩沖概率優化前是 4.63%,優化后是 0.48%。數據還是很可觀的。

 

來自:http://36kr.com/p/5084585.html

 

 本文由用戶 urbn5787 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!