1. 程式人生 > >【案例】新浪微博短視訊服務的優化實踐

【案例】新浪微博短視訊服務的優化實踐

本文將分享新浪微博短視訊如何提升使用者體驗、降低成本的思路與實踐,包括提升短視訊釋出速度,降低長視訊轉碼時間,通過新的 Codec 減少頻寬成本等。

作者:李成亞來源:新浪微博|2018-08-06 10:50

概覽

我所在的團隊主要負責新浪微博短視訊從客戶端的轉碼上傳到服務端的轉碼儲存的整條服務鏈路。今天主要向大家分享我們團隊在短視訊方面有關視訊編解碼的實踐與探索。

這是一個簡單的互動圖,表示典型的生產者、消費者和服務方之間的關係,他們在平臺中關心的重點也會有所不同。

需要強調的是,我們今天主要討論通過技術手段改進優化服務併為消費者帶來更加完善的產品體驗,關於使用者內容的部分並不在此次討論的範疇。

簡單總結下平臺中每方關切的重點:

  • 生產者關心視訊的釋出速度,也就是使用者通過微部落格戶端釋出一段視訊,從點擊發布按鈕開始到其他人能在微博上看到此視訊所需要時間的長短。
  • 消費者關心視訊的觀看體驗,例如是否卡頓,流量消耗等。
  • 服務方關心平臺的服務質量。

釋出速度

傳送流程與關鍵性問題

先來看釋出速度。首先向大家簡單介紹一下使用者通過微部落格戶端傳送視訊的流程。

客戶端是一個 iOS 或 Android 平臺應用。

首先,在客戶端我們會對視訊做一次壓縮,其目的是縮小視訊體積。

接下來視訊經過轉碼後會被作為一個整體檔案單獨上傳至 Web Server, Web Server 接收後會將視訊上傳到儲存服務,同時在服務端觸發轉碼操作。

此服務端轉碼的目的是:

  • 視訊規範化,統一輸出格式,排查視訊錯誤。
  • 視訊標記處理,為視訊新增水印或標識。
  • 自動截圖。接下來服務端轉碼後也會把此視訊檔案上傳至儲存服務,最後提示使用者視訊傳送成功。

我想大家可以很明顯地看出來這裡有三個關鍵性問題:

  • 整個視訊釋出是一個序列的過程。意味著一旦其中任何一個環節出現問題都會導致整個操作的失敗。
  • 服務端轉碼慢。因為曾經的服務端轉碼是一次性轉碼,我們為了減小視訊壓縮的體積使用了一個比較複雜的演算法。
  • 長視訊釋出的速度非常慢。曾經在微博上釋出一段最長一小時的視訊,其延時可達好幾個小時。

後來我們重寫或者重構了每條鏈路上一些關鍵節點的服務程式碼。

關鍵技術優化

下面我來介紹一下幾個關鍵的技術優化點:

(1)在客戶端,我們會將編碼與上傳合併到同一個流程裡,集成了一個監控編碼器的執行緒以監測編碼器完成 Gop 資料編碼的數量。

一旦此數量累計到一定閥值後會觸發客戶端的上傳操作,客戶端將這部分資料進行單獨分片並上傳至 Web Server,在 Web Server 收到所有分片之後會進行 Merge 操作,最後上傳至儲存服務。

(2)我們在轉碼端集成了一個排程模組,此模組會在釋出階段為視訊做一次低複雜度的編碼以縮短視訊的釋出延遲。

當完成這次低複雜度轉碼後,排程器會進行一次更高複雜度的轉碼,此轉碼完成之後原播放連結會被替換,整個操作流程對使用者而言是無感知的。

(3)對長視訊採取分片並進行轉碼。其大概過程是:首先一個輸入的視訊會被分離成音訊軌和視訊軌。

其次依據其 GOP,視訊軌會被切割成不同的分片,一個分片中可能包含多個 GOP。但一個 GOP 不會被分在不同的分片中,以避免最終視訊合併時出現丟幀而導致視訊觀看卡頓的問題。

最終分片完成後,每一片會被排程器分發到不同的轉碼器同時進行轉碼。

此時排程器會開啟一個監聽執行緒去監聽此視訊所有分片的轉碼任務,一旦排程器監測到最後一個分片已經處理完成便觸發一次 Merge 操作,就把視訊流的所有分片合併成一個視訊,最後再和音訊軌合併為一個完整的輸出視訊。

總結與結果

上述流程中我們主要做了以下三點優化:

  • 客戶端:將編碼與上傳合併為一個操作。
  • 服務端:分等級轉碼。在釋出階段只進行簡單複雜度的快速編碼。
  • 對長視訊進行分片並行轉碼。這裡的兩個關鍵點:A:分離音視訊。B:按 GOP 分割視訊流。

通過上述這些優化,我們可以提升視訊平均釋出速度至原來的 3 倍,提升長視訊釋出速度至原來的 10 倍以上,以上就是我們在視訊釋出階段主要進行的一些優化。

觀看體驗

下面我想與大家分享一些關於觀看體驗的優化,分享之前先為大家介紹一下產品形態與觀看場景:

(1)產品形態

這是目前微博上主流的兩個視訊類產品,左邊是一個資訊流中的視訊,其預設播放尺寸比較小而且基本上都以橫屏呈現;右邊是微博於 2017 年初上線的一個新服務“微博故事”,這是一個全屏播放並可新增 AR 特效的視訊產品,以上是微博視訊業務的兩種產品形態。

(2)觀看場景

觀看場景是指使用者會在什麼樣的場景下觀看微博視訊。首先,在網路環境上可能是 Wi-Fi 或行動網路;在終端裝置上可能是手機、Pad 或 PC;手機又可依據不同的作業系統、螢幕大小、硬體配置等等進行細分。

如果我們只做一些釋出階段的工作,使用者在不同場景下選擇不同產品形態看到的都是同一份檔案。這種方案可能在某些特定的場景下能夠帶來比較好的體驗,但是我相信對於大多數場景這種方案的體驗應該都不是最好的,甚至很糟糕。

服務端轉碼細化

第一項優化是在服務端進行轉碼的細化,簡單地說就是從原來的一個輸出變為多個輸出,這些輸出之間主要的差別大概是以下三個維度:

  • 解析度從低到高。微博視訊服務的解析度最低是 240P,最高目前是 720P,在未來還可以更高一些。
  • 編碼複雜度從簡單編碼到複雜編碼。
  • 視訊格式,例如 MP4、HLS 等等。

下發策略優化

我們會在客戶端構建一個定製化的下發策略,根據產品形態與使用者的網路環境、裝置型別、螢幕的尺寸等硬體配置來選擇一個符合此場景需求的編碼複雜度、解析度、格式等輸出引數。

通常情況下,我們選擇的輸出都是此使用者在此場景下能夠以足夠清晰度播放的較低位元速率視訊。

A/B Test

接下來要講的是一種常見方法叫做 A/B Test,大概分為四個步驟:定義指標、選擇對照組、變更設定、對比結果。

定義指標

詳細說一下定義指標。第一個是首幀播放延遲,簡單說就是從使用者點選播放按紐到視訊的第一幀畫面播放出來所需要的時間,包括下載時間、解碼時間、渲染時間等等;第二個是播放失敗率。

第三個是有效播放率,這裡我們有兩個和播放數相關的統計指標:總播放量就是隻要此視訊有一幀被成功播放就算一次,有效播放量是指此視訊連續成功播放多長時間,例如三秒鐘、五秒鐘連續的播放。有效播放率就是這兩者的比值。

選擇對照組

關於選擇對照組我們大概有兩種方式:第一種是隨機選擇,就是從所有的微博使用者中隨機抽取 20% 分成兩個對照組。

第二種是按特徵選擇,可以確定使用者具體的某一個特徵,例如是不是大 V 使用者或粉絲數量處於何種量級,甚至可以按照使用者登陸終端裝置不同來進行選擇。

變更設定

這裡我們主要在兩方面進行一些區分與調整:第一是編解碼引數,以  X264 具體來說就是 X264 的那些編解碼引數;第二是下發策略,有時候儘管兩個使用者可能處於同一個場景,但我們依然會下發一個不同的視訊並最終看哪個視訊的資料表現更好。

這裡其實還有一些其他的調整,例如是否啟用客戶端的軟編、硬編、或軟解、硬解等等。

對比結果

最後就是對比結果,這裡主要有兩點,第一是前文定義的核心指標變化情況是趨於優還是差,第二是客觀的視訊質量對比;我們也會藉助一些開源的工具來客觀對比視訊本身的指標,例如 PSNR 或者 SSIM,這也是 A/B Test 的主要內容。

需要說明的是,選擇對照組、變更設定、對比結果是不斷迭代的過程,通過不斷的去調整各種設定最終達到優化指標的目的。

上圖是指在 Wi-Fi 環境下微博自動播放的一種策略。既然是自動播放就涉及到一個問題:播放之前需要先下載視訊,那麼需要下載多少比較合適呢?

Wi-Fi 環境下自動播放

方案一:固定長度下載

一開始我們採取的是一種叫做“固定長度下載”的方案。簡而言之就是每個視訊都提前下載一部分固定長度的資料例如 265K。

當時此功能上線之後我們就發現了兩個比較明顯的問題:

第一是視訊下載伺服器佔用頻寬有很大的上升。因為自動播放的功能,當天的播放量已經上升到之前的兩倍多,其中一部分播放量最終回到視訊的下載原站;第二是有部分的視訊依然會出現輕微的卡頓感。

簡單解釋一下這兩個問題的原因,其實這兩個原因都和下載方式不正確有關係。

頻寬佔用飆升是因為自動下載導致使用者下載得太多,卡頓感是因為自動下載下的內容還不足以支撐流暢的播放體驗。

關於第二點需要解釋的是:我們知道對於一個視訊檔案,比如說 MP4,它的一些 Meta 資訊或 Moov 資訊是在頭部的,並且此資訊的長度與視訊本身的長度相關,也就是說視訊越長這部分的資訊提取量越大,所以對於一些短視訊自動下載 256K 可能太多,但對於長視訊下載 256K 又太少。

方案二:固定時間下載

我們想到了一種固定時間下載的方案,簡而言之就是對每個視訊都先計算好一部分例如前三秒鐘的資料大小,我們在服務端轉碼的同時會計算出此視訊包含的 Meta 資訊、Moov 資訊、前三幀的 MBAT 等加起來有多大。

在使用者瀏覽資訊流的同時和這些資訊將與播放連結一起下發至客戶端。需要進行解釋的是這個三秒是基於我們反覆調整測試最終得出的一個最佳值,可以在明顯消除自動播放卡頓感的同時控制頻寬的佔用。

提高視訊源的質量

之前微博對釋出視訊的壓縮門檻有了一個質的提升,從 480P 提高到了 720P,並且對全部的微博使用者都開放了此許可權。我們未來還可能實現 1080P 的上傳,可以看到隨著解析度的提升對比左右兩個視訊畫面差距十分明顯。

總結

簡單總結一下對於觀看體驗方面的幾項重要優化:

第一是我們依據定製化的下發策略根據使用者場景自動下發最符合此場景的視訊;第二是我們使用 A/B Test 來幫助不斷完善幾項核心指標,從而優化觀看體驗;第三是我們實現了 Wi-Fi 下的自動播放;第四是提升上傳視訊的質量。

服務質量

作為服務提供方的我們比較關心的問題可以概括成一句話:怎麼既穩定又省錢地提供高質量的短視訊服務?

這句話有兩個關鍵點:穩定、省錢。為了保證穩定我們做得更多的其實是一些類似於多機房部署等架構方面的工作,在此不再贅述。

降低成本

省錢,是指成本優化方面。在這裡主要有兩個降低成本的思路:

思路一:保持畫質,提高編碼複雜度,降低位元速率。

思路一可以簡單理解為一個用時間換空間的方案。我們知道隨著編解碼器的發展,在其編碼的複雜度越來越高的同時頻寬與位元速率是越來越低,同等位元速率下視訊質量越來越高。

以 H.265 為例,官方給出的比較有代表性的資料是 H.265,相對於 H.264 而言其編碼複雜度大概提升至後者的 10 倍,而位元速率能夠達到 H.264 的 50%。

如此高的一個編碼成本提升,如果是在客戶端或是服務端進行都是不現實的。於是我們構想了一種新的思路:熱門視訊的極限轉碼。

思路一優化:熱門視訊極限轉碼

  • 業務特點

簡單介紹一下,微博具有一個很明顯的熱點+長尾的業務特點,可能每天 TOP2000 或 TOP1000 部分的視訊會佔到當天視訊播放量的 50% 以上,而絕大部分視訊的播放量很低,只能佔 10%~20%。

根據此種業務特點,我們提出了這種只對一部分熱門視訊進行極限轉碼的方案,從而最大程度地節省計算成本,降低頻寬消耗。

  • 熱點判斷

如何判斷某個視訊是否為熱門視訊?我們主要從以下兩個方面:

第一是預判。在其釋出階段,我們根據釋出方的影響力預判其是否為熱門視訊,在這裡我們並沒有什麼非常複雜的機器學習演算法,而是可以簡單理解為根據使用者的粉絲數作出判斷。

第二是跟蹤。可能有些視訊在釋出階段並沒有被判定為一個熱門視訊,但是可能因為某位微博大 V 轉發了他的視訊或者因為這個視訊本身很有意思從而帶來播放量的爆發性增長。

在這裡我們會有一個程式去統計某個時間段 t 內全站播放量 Top x 的一部分視訊;隨後這部分中還未進行極限轉碼的視訊,會被排程器投放至一個工作佇列中進行極限轉碼。

這裡的一個小細節是我們的統計時間段 t 與統計視訊數量 x 都可根據機群的工作負載進行動態調整。

如果機群整體負載較高,我們會把這兩個數值調低以避免熱門視訊的轉碼對正常釋出視訊的轉碼任務造成過多影響;如果機群整體負載較低,我們就可把這兩個數適當調大以轉碼處理更多低位元速率視訊從而降低頻寬成本。

  • 方案選擇

關於方案選擇,在這裡我只是提供一些可供選擇的思路,大概是有三種:

第一是更換編解碼器例如 H.265 或 AV1;第二是使用一些機器學習的技術進行場景識別,判斷此視訊的型別,從而優化編碼過程。第三是使用雲服務,業內的一些雲服務提供商都能提供這種高複雜度轉碼能力的服務。

  • 意義與影響

通過採用對熱門視訊進行極限轉碼的方案,我們可以實現 20%~40% 的位元速率下降;而在目前所有微博視訊播放量中通過這種高複雜度轉碼處理的視訊的佔比可達到一半以上,與此同時日頻寬節省在一百 TB 以上。

思路二:保持畫質,保持編碼複雜程度,降低成本。

思路二是保持畫質、保持編碼複雜度的同時降低成本。上圖是一個比較簡單的視訊轉碼流程,從視訊輸入到解封裝,再到視訊的解碼與處理,經過視訊的編碼最後封裝與合併到輸出。此流程可以說本身已經沒有什麼優化的餘地。

思路二優化:多輸出轉碼

但這裡有一個前提就是其輸出並不是只有一個而是多個。這些輸出之間的差別可能就是解析度或格式,其他的大部分的引數是一樣的。

所以我們可以複用解碼的一個環節:可以看到上圖的後半段,在視訊流解碼完成之後視訊會被複製出多份,每份會進行單獨的視訊轉碼,緊接著複製出的每一個流會與音訊流合併成一個單獨的輸出,最終通過此方式我們可以同時轉出多個輸出。

  • 意義與影響

通過這種方式,我們可實現整體轉碼耗時節省 15% 左右。

降低叢集冗餘度

我們都知道現在很多的網際網路業務都會面臨一個流量明顯變化的過程,例如一天中某個時間段會出現流量的高峰或低谷。

如果希望叢集能夠經受住流量高峰的考驗就需要保持一個比較高的冗餘度,可能需要保持 1.5 甚至 2 倍的冗餘,才能在流量高峰時段保證網際網路服務的穩定進行。

以下是關於此方面我們進行的一些工作:

消除差異

首先,在整個短視訊服務的環節中,整條鏈路由以下四個服務構成:上傳服務、轉碼服務、儲存服務、業務服務。

這些服務所需要的配置、執行環境,甚至實現語言都是不一樣的,而每個服務都有自己的流量高峰與低谷。

這便導致了這樣一個問題:如果按傳統方式,需要每個服務始終保持一個比較高的冗餘度,那麼所有服務加起來整個叢集的冗餘度就會顯得非常高,從而造成一些浪費。

所以我們需要做的是抹除這些服務之間的差異。具體來說是通過最近幾年在後端領域很火的 Docker 技術將包括配置程式碼在內的整個執行環境打包成一個映象,可以簡單理解為一個壓縮包。

我們所有的服務依賴的都是這種 Docker 服務,只要在機器上安裝 Docker 軟體就可以隨時啟用所需服務。通過這種方式可以將之前處於高冗餘度下的四個叢集轉變為一個叢集,此機群只要保持一定的冗餘度就可完成服務的承載。

定時擴容

上圖是微博大致的每天流量變化趨勢,最右邊那部分是晚 8 點到次日凌晨 0 點的晚高峰,可以說幾乎每天流量都是以這種趨勢變化,晚高峰時段流量會比白天大部分時間段高出 20%~30% 的樣子。

面對這種情況我們會在高峰時段通過一些公有云服務擴充出的一些計算資源承擔這部分高峰流量;當高峰期結束便撤下這些公有云服務以儘可能降低服務的整體成本。

彈性擴容

上圖是之前鹿晗發微博公開戀情的半個小時內,微博一些核心服務的流量變化。可以看到從 12 點的值到最高峰,不到半個小時流量基本翻了 4 倍。

這種量級的上漲是無法通過諸如降級或流量調配等人工干預手段有效應對,這便要求我們的伺服器必須具備快速且大批量的彈性擴容能力。

當天我們也是從阿里雲上緊急擴容了超過一千臺的伺服器,最終將此熱點事件造成的流量爆炸性增長化險為夷。

成本優化總結

簡單總結一下我們在成本優化方面做的一些工作:

首先是對熱門視訊進行極限轉碼,通過以最小的計算資源去獲取最大頻寬節省來降低成本。

其次是我們多輸出轉碼,整體上降低一些編碼的成本,隨著釋出的視訊的質量越來越高,多輸出轉碼降低成本所帶來的收益應該會繼續提高。

第三是根據業務的流量變化通過一些彈性擴容的手段來動態調整叢集的規模。