本文為轉載文章,文章來自:王輝|十億級視頻播放技術優化揭密 QCon是由InfoQ主辦的全球頂級技術盛會,每年在倫敦、北京、東京、紐約、聖保羅、上海、舊金山召開。自 2007年 3月份首次舉辦以來,已經有超萬名高級技術人員參加過QCon大會。QCon內容源於實踐並面向社區,演講嘉賓依據熱點話題,面向 ...
本文為轉載文章,文章來自:王輝|十億級視頻播放技術優化揭密
QCon是由InfoQ主辦的全球頂級技術盛會,每年在倫敦、北京、東京、紐約、聖保羅、上海、舊金山召開。自 2007年 3月份首次舉辦以來,已經有超萬名高級技術人員參加過QCon大會。QCon內容源於實踐並面向社區,演講嘉賓依據熱點話題,面向 5年以上工作經驗的技術團隊負責人、架構師、工程總監、高級開發人員分享技術創新和最佳實踐。
4月18日性能優化面面觀專題會議上,騰訊研發總監王輝以“十億級視頻播放技術優化揭秘”為主題,用QQ空間的日均播放量一年內從千萬級突破到十億級所面臨的嚴峻考驗為切入點,為大家分享視頻團隊在視頻組件的整體架構、優化效果衡量、帶寬優化、秒開優化、緩衝優化、成功率優化等六個方面的技術實踐。
王輝:大家早上好!我叫王輝,來自騰訊,從2009年開始從事QQ空間技術研發,近期主要關註手機短視頻、視頻直播、AI智能硬體。很高興能在QCon上與大家一起分享和交流。我今天的話題是“十億級視頻播放技術優化揭密”。主要介紹我們團隊在去年一年短視頻風口上,我們的視頻播放量從5000萬到十億級過程中的一些技術實踐,希望我的介紹能給大家做一些借鑒和參考。
眾所周知,短視頻去年是一個風口,起因是來自Facebook 2015年Q3的財報,財報表明在Facebook平臺上每天有80億次短視頻播放,給Facebook帶來了強勁的廣告收入,正是這個數據給國內核心大公司和創業公司帶來的一些新的突破口。其實短視頻已經不是一個新的概念,從2006年開始國內就有很多公司在做短視頻。隨著Facebook吹起短視頻風,去年在短視頻行業有近百款應用出現,中國網民裡面每5個裡面就有1個是短視頻的用戶,短視頻成為互聯網的流量入口。QQ空間也在這個風口中,從2015年11月份的每天5000萬視頻播放量,經過一年的耕耘細作,徒增到2016年12月份的10億量級,現在還在不斷增長。
我的演講主要是按照我們產品迭代的幾個關鍵步驟展開:
首先是快速上線,2015年我也是跟隨著大家的體驗快速上線了新短視頻的體驗;
其次面臨的是成本問題,在做的過程中做了一些成本的優化工作;
然後是體驗優化。在解決成本問題之後,短視頻的觀看體驗要做到極致。比如說視頻的秒開、不產生緩衝、不卡、成功率的提升。
快速上線
在開始之前,我先介紹一下我們的團隊職責,我們團隊負責手機QQ和手機QQ空間兩個APP,每個APP有iOS和Android兩個團隊,一共四個團隊,四個團隊負責兩個APP。在這個項目中,我們四個團隊要針對兩個平臺實現四套邏輯,這裡的效率是存在一定的問題。
關於短視頻體驗,在這之前,我們也只是做到能播放而已,沒有做很精細的工作,並且這裡的產品觀感體驗也不是很一致,也不是很好。
技術上,之前也只是做很基礎的架構,直接由播放器連接伺服器下載數據,達到能播放就可以。之前我們沒有積極去做這個事情,導致播放成功率低、失敗原因未知、不支持邊下邊播、緩衝時間比較長等問題,流量浪費也比較嚴重。在產品上要解決的,是在整個APP裡面把所有產品的體驗做到一致,比如說每個功能的觀看體驗,視頻浮層的體驗,統一觀看體驗也為我們項目清除了很多障礙。
而這裡的技術上的要點是非常關鍵的,第一個是邊下邊播,這是基礎的要求,是為了加快視頻播放速度。第二個是流量的控制,這麼大的平臺,之前只是做5000萬的播放量,如果沒有流量控制的雲策略,可能到後面流量是無法把控的。第三,剛纔講到團隊的現狀,團隊要負責兩個APP,這裡要做代碼復用,不可能再像之前一樣四個團隊維護四套代碼,第四,我們支持第三方的視頻源。第五,需要完善監控上報,對業務知根知底。
可以看到,完成核心技術要點最核心的一點是如何控制視頻的下載,傳統的方式是播放器直接塞播放地址給播放器,它就可以直接播放,這其實是一個黑盒。我們在中間加了一個本地代理,播放器與伺服器的數據請求,我們完全可以把控。在這個過程中,比如說播放器要數據時,可以給它更多的數據,這樣能解決它緩衝的問題。有了這層代理之後,架構也更清晰一點。
基於這樣的架構,在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視頻給你播放。從而保證軟體解碼柔性可用,針對視頻源規格按機型適配降級,保證用戶視頻播放體驗。
經過我們的統計,外網上有94%的手機還是支持H.265解碼的。支持1080P手機的解碼占46%.
編碼只能在後臺做,如果在視頻後臺進行全面編碼的話,是不現實的。因為編碼複雜度呈指數級上升,拿後臺伺服器進行編碼也是不可行的。我們的做法是只用熱點視頻進行後臺轉碼,不是所有視頻都去編碼,對觀看量在TOP N的視頻進行編碼,只需要編碼少量的視頻就可以帶來流量優化效果,因為TOP N就占了全網80-90%的流量。
因為熱點視頻的熱點轉化很快,可能前幾分鐘是熱點,後幾分鐘就不是熱點,因為社交網路的傳播非常快。我們給後臺的要求是轉碼速度一定要快,在之前沒有優化時,轉一個10分鐘的視頻要半個小時左右。後來我們做了分散式處理之後,轉10分鐘的視頻只用兩三分鐘。一些短視頻最長5分鐘左右,只要監測到這個視頻很熱的話,1分鐘之內就能轉出來,就是H.265了。
同樣,在H.265編碼器上做了一些優化,比如說編碼速度和碼率的都會有提升。
上線H.265優化之後,我們的帶寬進一步下降,節省了31%左右。
秒開優化
帶寬問題解決之後,面臨的下一個問題是體驗優化。用戶最想要的是視頻能立馬播出來。我們定了一個秒開技術指標,只要這個視頻從到我的視野範圍,到視頻播出來之間的耗時在一秒以內。這也是對標Facebook的體驗,Facebook一打開動態,視頻是能立即播出來的,不需要等待就能播,這個體驗其實很順暢。核心的流程主要是三個步驟:1、客戶端的耗時;2、下載數據;3、等待播放。
這裡主要有兩個大的耗時點,第一下載視頻數據耗時;第二個是客戶端的耗時,下載視頻數據耗時的話,主要是下載數據量和下載的速度。
這裡有一個很直接的問題,播放器需要下載多少數據才能播放?我們可以看一下MP4,MP4其實是一個比較靈活的容器格式,每個東西都是用Box表達的,每個Box又可以嵌入到另外一個Box。MP4主要由MOOV和Mdata組成,MOOV是囊括了所有的視頻關鍵信息,肯定是先把MOOV下載完之後才能找視頻數據才能播起來。不巧的是,在我們外網會發現有5%左右用戶上傳的視頻,它的MOOV是在尾部的。後來也發現,有很多安卓手機比如說山寨機,一些攝像頭處理的廠商可能比較偷懶,因為他們只有在你採集完信息之後才能知道他所有的信息,他可能把所有的信息放在尾部。對於MP4來說,一開始把頭部下載了,下載頭部時可能找不到這個MOOV,就猜測這個MOOV在尾部,我可能就有一次請求去探測這個頭部到底在哪?這個探測的話基本做法是去尾部探測。如果MOOV在其他地方的話,這次播放肯定是失敗的。現在主流的系統都是去尾部進行一次探測。
比如安卓某些手機是無法自定義Range,那就需要下載完整個文件才能播放。我們的處理方式,用戶在後臺做一次轉碼修複,客戶端採集後做一次轉碼修複。
再看一下Mdata,這是視頻的原數據。目前大部分是H.264編碼,H.264通過真預測的方式來進行視頻編碼,這裡有一個GOP概念,也是在直播裡面經常談的。一般的視頻需要下載歌完整的GOP數據才可以播,可以看到在這個裡面需要下載多少數據才能播呢?每個播放器的行為也不一樣。大家可以看到iOS要下載一個完整的GOP才可以播。像FFmpegBasedPlayer的話我可能只需要關鍵幀就可以播出來。安卓是比較尷尬的一個系統,在6.0級以下,可能需要5秒視頻數據才可以播起來。如果說是需要下載5秒數據才可以播起來的話,那肯定是非常慢的。我們這裡的一個策略會採用FFmpegBasedPlayer自己來做解碼,這裡要關註功能性和耗電的問題。
解決了Mdata之後,你會發現如果我的數據在頭部,拿關鍵信息進行播放的話,其實我播放的數據量非常小的。
對於下載優化的話,會有一個防盜鏈的請求,通過HTTP拿到真實的才可以下載數據。在手機上執行HTTP請求是非常耗時的,這裡我們走私有長連接通道做這個事情。
關於優化下載鏈路,這裡也是談的比較多的,一般也是直接輸出IP地址,利用IP地址做跑馬的策略,兼顧性能的效率,這個是用的比較多的方式。
進一步思考,按照普遍600K碼率的話,我們統計到現在APP上面下載的平均速度是400K左右,這樣計算的話,可能在安卓上面播放一個視頻的話,需要將近0.9秒左右才可以下載到你需要的數據。如果碼率再進一步提升的話,可能會更大,這其實我們也做了一些場景分析,會發現我們是社交網站,它有好友動態,視頻在好友動態里播放,或者是在視頻浮層里播放,我們的選擇是預載入的策略,這也是常見的策略。我們會在當前看的這條動態時會預載入後面視頻的關鍵信息,比如說會載入頭部信息和需要播放的數據,來進行預載入。比如說在播放當前視頻時,我的視頻在載入一定數據之後會載入下一秒預載入數據,這些都可以做到的。
預載入有一個問題,我們之前踩了一個坑,可能預載入視頻時還是要優先圖片的。視頻當然重要,但是社交網路上的圖片也更重要,可能在預載入視頻時會考慮到圖片的一些任務,還有視頻封面之類。
優化效果也是比較明顯,經過剛纔幾個策略,一個是我們對頭和播放器的處理,我們對防盜鏈的處理,還有對下載鏈路的處理和預載入,這樣我們的耗時大幅度減少了,之前是1.8秒降到0.6秒左右。客戶端的性能也是讓人容易忽視的問題,發現有些用戶雖然有視頻的緩存,但是播起來還是很慢,這其實是客戶端性能的影響。因為視頻涉及到的BU和流程比較多,在這個過程中還要更關註到客戶端的影響,要分析下客戶端是哪些在搶占你的視頻播放資源,我們之前犯過一些錯誤,md5會卡住一些流程,或者是HttpParser會阻止你的任務,會導致視頻播放更慢。
在優化視頻播放過程中,我們在4月份也做直播。直播這裡面插入個事情,我們要播放直播的視頻流,是HLS的視頻,在好友動態裡面可以觀看直播的內容。HLS在安卓上面體驗非常差,因為安卓3.0之後對HLS基本沒有做的優化工作,這裡每次安卓上播放HLS需要等待6-9秒。分析發現它的處理也不是很得當,因為安卓系統請求鏈路較長,串列下載,需要下載3-4片TS才能啟動播放,下載3個分片的話,耗時就會很久。之前提到我們這裡有代理,有了代理之後做事情方便很多了,通過里獲取M3U8,解析M3U8裡面有哪些文件,可以做並行下載,只讓他下載一次M3U8,這樣下載速度大幅度提升。回到剛纔架構上,有了下載代理層的話,你可以做HLS的加速和管理,可以加入HLS的視頻源。
HLS緩衝耗時也是很明顯的,之前需要6秒左右,現在1.6秒左右就可以播起來。整體從之前的2秒左右現在優化到700m秒,80%用戶都可以在1秒內播視頻。
還有一個是用戶比較關註的問題,觀看視頻時卡,觀看一會卡了一下,loading數據,loading完以後又卡,這個體驗非常差,我們希望所有的視頻都不卡。其實這有兩個播放場景,一個是正常場景,邊下邊看,數據在下載。對於正常場景下載時會做一些帶寬調整,在低速時會做切換IP的處理,比如說當前連通IP的耗時比較久的話,會做一些處理,也會對網路進行速度限制。
針對Seek場景的話,如果用戶拖動的話,文件緩存系統是連續存儲系統的話,必然會造成拖到這裡時,後面的緩存數據是沒有辦法下載到系統裡面來的。
我們就對存儲做了一次重構,支持文件空洞。會按照一兆的方式對文件進行碎片劃分,好處是我可以分段存儲,我可以允許邏輯空洞的,拖動的話也可以在後面存儲,也不需要資料庫,我可以知道這是從哪個位置到哪個位置的存儲。這樣淘汰緩存也高效一點,並可以制定更靈活的緩存策略。這裡可以淘汰更低密度的文件,還可以做的事情是對文件加密。這裡產生卡頓的用戶裡面,90%是因為進行拖動,拖動之後又沒有緩存數據,所以這裡有可能導致發生緩衝。統計效果也是比較明顯的,上了分片緩存之後,之前的緩存概率是4.6%左右,最後下降到0.48%,基本上看不到發生緩衝的場景。
成功率優化,也是我們比較關鍵的指標。成功率優化沒有捷徑,可能是Case by Case各個擊破。之前我們進行編碼,有幾百個錯誤碼,錯誤碼原因進行上報,每次進行迴圈,一個個錯誤碼進行解決。下載常見的錯誤碼,DNS劫持是比較多的,一些網路運營商會劫持你的請求。
這個在國內是比較常見的劫持,有的小運營商按月會劫持你的視頻內容,可能直接污染你的DNS讓你查找不到CDN,這是比較多的,還有一些網路不穩定的影響導致。更隱藏的會直接污染你的視頻內容,讓你視頻內容是錯誤的。播放比較多的可能是一些編碼的原因,剛纔提到一些手機採集出來的視頻在低端手機上播不出來,我們會對這些視頻進行修複。
邏輯上的問題,因為播放器有狀態的,可能開發人員比較多,每個人過來加一個邏輯的話,會導致播放狀態出現問題。
我們做的播放器錯誤解決方法:
HOOK播放器介面與回調,實現播放器狀態機,監控插放器API的調用是否合法,不合法直接告警或Crash。幫助開發快速定位問題,同時減輕測試同事的負擔,封裝成UI組件,使其它開發不必理解播放器。
最終優化的成果是這樣的,下載成功率優化前是97.1%,優化後是99.9%。播放成功率優化前是97.0%,優化後是99.9%。首次緩衝耗時優化前是1.95s,優化後是0.7s。二次緩衝概率優化前是4.63%,優化後是0.48%。數據還是很可觀的。
我的演講基本是這些,歡迎大家關註我們團隊的公眾賬號,也會分享一些技術文章。
Q&A
問題1:剛纔您提到已經開始嘗試用265了,能透露一下265你們播放的在整體中占多大的比例?
王輝:現在熱視頻裡面80%都是H.265。10億裡面會有70%、80%左右。
問題2:推進的還是挺靠前的。剛纔你提到要判斷手機的H.265能力,用大規模的浮點運算,首先我先瞭解一下你們用的什麼浮點運算的Mark?其次,為什麼要用浮點運算?其實視頻編解碼裡面幾乎全部都是整數運算。
王輝:浮點運算能代表你這個手機性能,其實我們是評估性能的,不是評估H.265轉碼,如果性能達到的話,解碼也是可以達到的。
問題3:如果想針對解碼做評估的話,我建議整數運算。你可以確認一下,首先視頻編解碼的標準規定是沒有浮點運算,不同的編解碼時限可能會插入少量的浮點運算,大部分是整數運算。
王輝:我們初步做的時候是判斷手機有沒有運算能力來做的浮點運算判斷。
主持人:感謝各位嘉賓的提問,感謝王輝老師給大家帶來的講解。