愛奇藝奇秀直播的秒播體驗優化實踐

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在視頻直播中,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"首幀渲染速度","attrs":{}},{"type":"text","text":"會直接影響用戶體驗。想象一下,你興致勃勃進入了一個愛豆的直播間,進入直播間後遲遲不見直播畫面,而是長時間停留在直播間背景圖上,這是大多數用戶都無法接受的體驗。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了提高用戶在","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"愛奇藝直播和小視頻平臺奇秀app iOS端","attrs":{}},{"type":"text","text":"的觀看體驗,愛奇藝去年中旬對","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"奇秀秒播","attrs":{}},{"type":"text","text":"進行了整體的優化,主要涉及","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"業務邏輯以及視覺上","attrs":{}},{"type":"text","text":"的優化。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":16}},{"type":"strong","attrs":{}}],"text":"01 問題出在哪兒?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從進入直播間到第一幀畫面渲染。","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"播放流程一般涉及如下幾個方面:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/bb/bb2fb45bef6b1ade0e0a22a72fadf07f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分析耗時操作,首先要找到耗時較多的邏輯。這裏嘗試了兩種方法:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"打印日誌。","attrs":{}},{"type":"text","text":"在進入方法前、方法執行結束後,打印日誌,輸出方法的耗時。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"利用埋點投遞。","attrs":{}},{"type":"text","text":"在秒播路徑中設置若干關鍵節點,每個節點觸發時,將耗時數據投遞到神策。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於打印日誌,在實際操作的過程中,發現有比較明顯的弊端,比如:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)測試次數一般不會很多,所以","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"不具有代表性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)進入","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"不同的直播間、在不同的網絡狀況下","attrs":{}},{"type":"text","text":",都可能會影響到","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"測試數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了保證分析數據的準確,最終採用","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"埋點投遞配合TimeProfile的方式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先將秒播的過程分成","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"幾個重要的階段","attrs":{}},{"type":"text","text":":進入直播間、房間數據請求返回、準備播放、第一幀渲染成功。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過埋點,統計出不同階段的耗時情況。這裏以優化前的5.5.0版本舉例,如圖所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/bf/bffe8918c3339d771144e0cd0cd18789.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從圖中可以看到,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"房間數據請求解析階段以及播放階段耗時較長。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"縮小了問題的範圍,我們使用","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"XCode自帶的調試工具Time Profile進行具體的耗時分析。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TimeProfile的原理是通過按照固定的時間間隔來跟蹤每一個線程的堆棧信息,通過統計比較不同時間間隔之間的堆棧狀態,來推算某個方法執行了多久,並獲得一個近似值。如圖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a2/a212bbeaf4136912f8e54442cfbf583a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對多次測試數據進行對比發現,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"具體的耗時邏輯主要有兩處:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)播放器SetFrame操作會卡主主線程較長時間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)處理房間接口返回的數據消耗的較多的時間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":16}},{"type":"strong","attrs":{}}],"text":"02 如何解決?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先,最亟待解決的問題是","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SetFrame導致卡頓的問題","attrs":{}},{"type":"text","text":",通過與播放內核同學的溝通,猜測","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"可能與蘋果系統的轉場動畫有關(疑似資源爭搶,播放器短時間內獲取不到上下文)","attrs":{}},{"type":"text","text":",導致播放器在系統進行動畫的過程中去爭搶相關資源,最終導致第一幀渲染失敗。所以這裏引入狀態機來解決這個問題:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/55/552775350c8a412994e22c467c0c1a96.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有的播放操作都等到系統告知我們UI佈局結束後再去操作,這樣調整後,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"秒播回到正常的區間(大概56%左右),且未再復現卡頓問題。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其次,對於處理接口返回的數據,進行的一系列初始化操作耗時較多的問題。","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"具體分爲2點:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)初始化各個功能模塊會導致耗時較多,比如聊天區歷史消息功能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)由於iOS要求UI相關的操作需要在主線程進行,所以接口請求返回後,存在多次異步到主線程的邏輯,非常消耗時間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對功能模塊初始化耗時問題,我們在直播間抽象了一個","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"功能管理模塊,一方面是控制模塊的加載時機,另一方面可以將功能模塊與直播間解耦。","attrs":{}},{"type":"text","text":"如圖:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fb/fb9386b8d2801ca02092b451489455e4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"重複異步到主線程","attrs":{}},{"type":"text","text":"的問題,我們在底層對","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"所有的網絡請求","attrs":{}},{"type":"text","text":"都進行一次異步到主線程的操作,這樣就不用在業務層由開發同學再進行異步主線程的操作了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"這個問題改動之後,秒播提升較爲明顯,大概穩定在78%左右。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b9/b923b02252abb7af1d77adba631be4e5.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":16}},{"type":"strong","attrs":{}}],"text":"03 一些非技術相關的調整","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面主要討論的是","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"從外部進入直播間的秒播優化","attrs":{}},{"type":"text","text":",我們還有一種比較重要的切換直播間的方式——上下滑切換。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於上下滑技術上的相關優化,我們放在下一個章節說明。我們討論一種通過","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"一些視覺上的處理","attrs":{}},{"type":"text","text":",讓上下滑操作中的秒播","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"看起來\"更快\"一些。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相較於之前先加載直播間UI的方式,新的方式延遲直播間相關UI的創建(拿到房間數據後再創建),由於觀衆首先看到的是直播畫面,所以會給人一種播放的\"更快\"的錯覺。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5c/5ca73be81ffb41d36dde573c041ca980.gif","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":16}},{"type":"strong","attrs":{}}],"text":"04 繼續改進的方向","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再看看技術方面。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前針對上下滑也做了一些優化,主要是在滑動操作中,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"當手指離開屏幕時判斷出動畫結束時是否會滑入到下一個直播間,從而提前加載播放數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相對於之前等待完全滑入到下一個直播間後,再加載播放數據,有了一定的提升。但實際上還存在着","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"一些缺點","attrs":{}},{"type":"text","text":",比如:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)已經判斷出要滑動到下一個直播間,但在滑動動畫結束之前,用戶突然觸摸屏幕導致滑動中止。這時如果用戶放棄滑入到下個直播間,而是返回剛剛的直播間,那麼就要重新加載播放數據,體驗不是很好。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)在用戶開始滑動到手指離開屏幕,這段時間其實什麼都做不了,浪費掉了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於滑動切換直播間這個操作,目前更好的實現方式是使用","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"雙播放器,","attrs":{}},{"type":"text","text":"這樣在開始滑動時,就可以直接加載下個直播間的數據,從而避免了對於一些特殊情況的複雜邏輯處理並且","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"最大限度地提前了加載的時間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但由於我們的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"播放內核較大,目前採用雙播放器會導致直播間架構複雜度上升,邊際成本較高","attrs":{}},{"type":"text","text":",所以沒有再進一步嘗試雙播放器的方式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":16}},{"type":"strong","attrs":{}}],"text":"05 結語","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"通過對邏輯、視覺效果的優化,最終將秒播率提升至78%左右。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了通過一些新的機制(","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"比如上面提到的延遲加載、模塊管理","attrs":{}},{"type":"text","text":")來保證後續版本迭代時不會對秒播率造成影響,還會嘗試雙播放器來進一步提升秒播率,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"爲用戶帶來更好的播放體驗。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章