通過敏捷快速實踐 QUIC ,網易新聞在3個月內,將端內 QUIC 請求占比提升到 75%+,如 圖1 所示,并將客戶端請求平均響應時間 RT 降低了 45%,請求錯誤率降低了 50%+,視頻卡頓率降低了 25%+。
圖1 客戶端 QUIC 請求占比
(黃色部分為 QUIC 請求,藍色部分為其他協議請求)
如何做到以最小的成本、最小的風險和最大的收益接入 QUIC,是本文討論的核心。
什么是QUIC?
QUIC 是 Quick UDP Internet Connections 的縮寫,意為“快速 UDP 網絡連接”。QUIC 由 google 實現于2013年,是一種網絡傳輸協議,旨在提升網絡傳輸速度。2015年,QUIC 被提交到 IETF,目標是成為下一代的正式網絡規范,2018年,HTTP over QUIC 被 IETF 重命名為 HTTP/3。
在 UDP 之上,QUIC 實現了類似 TCP 的丟失重傳機制,QUIC 傳輸以數據包級報頭發送,并對每個包增加了單調遞增的數據包號來代表傳輸順序,當檢測到必要幀丟失時,QUIC 會將必要幀綁定到新數據包重發。QUIC 對報文頭部和數據也都進行了加密,且建聯時改進使用了 DH 密鑰交換算法,在防劫持方面也具有一定優勢。
所以,QUIC 雖然基于 UDP 實現,但在功能上等價于 TCP + TLS + HTTP/2,除此之外,相較于傳統的 HTTP + TCP,QUIC 還具有多項改進網絡傳輸的優勢,其部分優勢如 圖2 所示。
圖2 QUIC表現優勢
QUIC 目前分為 gQUIC 與 iQUIC 兩種,gQUIC 即為最初的 Google QUIC,而 iQUIC 是后來 IETF 制定的通用傳輸協議,如 圖3 所示。
圖3 QUIC分類
相較 iQUIC 而言,gQUIC 目前的應用較為普遍、成熟,如 Cadddy 支持 gQUIC,客戶端還有 Chromium 的 Net 庫 Cronet 也可以支持 gQUIC,包括 ExoPlayer 等三方庫也都提供了對于 gQUIC 的擴展支持。目前來看,選擇 gQUIC 對于渴望改善網絡傳輸情況的開發者來說,在接入成本和接入效率上具有優勢。
QUIC 接入策略
為了快速接入并驗證 QUIC,在流量入口設計上,我們選擇用 Nginx + Caddy 方案實現;在客戶端網絡庫上,我們選擇了 Chromium 的網絡庫 Cronet,原因如下:
- Google 對 Chromium 開源多年,已經過眾多軟件團隊的驗證,基礎功能穩定良好;
- 作為 Chromium 的網絡庫,Cronet 的跨平臺性良好,在 Android 和 IOS 雙端可可直接接入;
- gQUIC 相比 iQUIC,在各方面支持都更成熟,Cronet 也可以直接支持 gQUIC;
2.1 流量入口
流量入口設計上,由 Nginx 負責處理 HTTP 請求,Caddy 負責處理 UDP 請求,如 圖4 所示。
圖4 流量入口設計
2.2 網絡庫方案設計
在客戶端網絡庫處理上,如何能保證侵入性最小,風險性最低,并最快接入 QUIC,以驗證線上收益,成為了項目的主要目標。
由于客戶端用戶規模較大,一些量級較小的第三方 QUIC 處理庫使用存在一定風險性問題,而自研 QUIC 庫支持的成本和效率遠遠達不到預期,且 QUIC 的網絡改善收益對于 Team 來說是未知的,選擇一款穩定可靠的網絡庫來快速達到 MVP(最小可行性) 是首要目標,所以在 Android 和 iOS 端,我們都選擇了使用 Cronet。
2.2.1 Android
Android 端目前使用的網絡庫是 OKHttp,為了更清晰有效地驗證 QUIC 的效果,我們在接入 Cronet 的同時,也保持了原有網絡庫 OKHttp 處理邏輯的不變,通過動態配置控制 AB 策略。上線后通過逐漸切量,一部分網絡請求走 Cronet,一部分網絡請求走 OKHttp,以清晰對比出二者的差異。
而端內目前的兩套數據上報機制,一種基于 OKHttp 事件監聽實現,一種通過 Hook OKHttp 的事件監聽實現,而 Cronet 的上報與 OKHttp 事件回調可以對齊統一,可維護性良好,再次增加了我們選擇 Cronet 的理由。
2.2.2 iOS
Cronet 在 iOS 接入方面,API 設計友好,基于 NSURLProtocol 通過網絡攔截即可實現。iOS 的接入流程可以簡單分為初始化 Cronet 和注冊 NSURLProtocol 協議兩個部分。
2.3 網絡庫接入
2.3.1 Android
在接入 QUIC 時,Android 使用網絡庫 OKHttp 的攔截器(Intercept)機制來處理網絡請求較為便捷,當網絡請求從業務頂層通過 OKHttp 傳輸到 Cronet 對應的攔截器時,會交由 Cronet 處理。
2.3.1.1 攔截器處理
OKHttp 攔截器(Intercept)設計基于責任鏈模式,由于在攔截器中接入 Cronet 后,網絡請求會被 Cronet 庫攔截處理,造成后續的攔截器短路,中斷 Request 與 Response 信息在攔截器中的傳遞,所以 Cronet 的攔截處理就應盡量下沉,置于頂層應用攔截器的最底部,如 圖5 所示。
圖5 QUIC攔截器處理
而對于下層的默認攔截器和自定義網絡攔截器都將被 QUIC 短路,默認攔截器中主要提供了緩存、Gzip 解壓、建聯等處理,其中一部分處理策略由 Cronet 也可以替代實現,而重定向一類策略在 Cronet 監聽回調中處理也較為便利。
使用 Cronet 發起請求提供兩種實現,一種是 CronetUrlRequest,另一種是符合 HttpURLConnection 標準的,在 CronetUrlRequest 基礎上封裝了流操作的 CronetHttpURLConnection,由于客戶端涉及多媒體場景較多,使用 CronetHttpURLConnection 更能滿足大部分需求場景。
目前,我們在視頻、圖集、列表通用業務網絡請求等范圍全面實現了 QUIC 的接入。
2.3.1.2 數據衡量
為了更明顯地對比出 QUIC 與 HTTP/HTTPS 之間的數據變化,我們使用了兩套網絡數據監測機制:全鏈路統計和 APM ,以精準捕獲特定請求事件的時間戳,來計算并上報建聯時間、響應時間等信息。
通過 Cronet 提供的一些回調,可以實現與 OKHttp 上報監聽的邏輯統一。Cronet 提供的 RequestFinishedInfo 可以獲得 Request 的建聯等信息,提供的 UrlRequest.Callback 可以獲得響應等信息,而使用 RequestFinishedInfo 會增加一部分監控邏輯,對 Cronet 有輕微的性能折損,僅使用 UrlRequest.Callback 返回的部分響應信息也足夠得出 QUIC 性能數據,全鏈路上報 OKHttp 與 Cronet 監聽對齊方案如 圖6 所示。
圖6 全鏈路上報事件
由于 Android Cronet 的 CronetHttpURLConnection 在設計上較為封閉,擴展性并不是十分良好,比如響應回調 UrlRequest.Callback,或是內部實現的阻塞隊列控制 MessageLooper 都沒有暴露給開發者,在此基礎上定制一些功能實現,如全鏈路上報,或是 CronetHttpURLConnection 沒有提供的超時時間策略,都不是很方便。
為了解決這個問題,我們建立了一層代理和裝飾器,通過攔截 CronetEngine 可以拿到 CronetHttpURLConnection 的 UrlRequest.Callback,對此再做一層包裝,由包裝類進行統一的事件分發,將 Response 事件分發到了 OKHttp 的全鏈路處理器中,進而實現了全鏈路上報設計的統一。
2.3.1.3 遇到的問題
(1)超時時間處理
由于 CronetHttpURLConnection 提供的部分超時時間設置是空實現,而通過 Native Cronet 設置的超時時間也并不符合預期,通過 ConditionVariable 實現超時也未免過于冗余。
CronetHttpURLConnection 內部維護了一個類似于安卓處理管理機制 Message + Looper 的 Task 處理器——MessageLooper,MessageLooper 中維護了一個阻塞隊列,并提供了超時的控制策略,通過建立同包名類間接繼承 package 訪問權限的 MessageLooper,通過反射替換封閉的 MessageLooper 為 NRMessageLooper,進而可以獲得超時時間的靈活控制權,在此基礎上,我們增加了超時時間的動態下發,以便于風控配置。
對 Cronet 庫的定制如 圖7 所示。
圖7 網絡庫定制架構圖
(2)請求占比優化
最初,客戶端 QUIC 協議請求占比在統計上報上來的數據觀測中并不理想,為了提升 QUIC 占比,我們在與 CDN 共同排查后,優化了雙方的處理方案,客戶端轉用 CronetHttpURLConnection 處理,CDN 側同時優化處理,并對網絡節點也進行了相應調整,保證了兩側方案的統一性,并再次降低了平均響應時間與錯誤率。
2.3.2 iOS
在 iOS 網絡庫接入方面,調用 Cronet 的 setMetricsEnabled 接口開啟 Metric,通過 URLSession 回調獲取 networkProtocolName 屬性,可以獲取當前網絡請求的協議類型,以更有針對性地進行數據衡量。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0))
QUIC 項目上線
3.1 切量控制
由于 QUIC 改善的擁塞控制與更低的建聯時間,都傳遞給我們了一個信息:QUIC 對改善視頻卡頓等場景有所增益,所以,我們最初的方案選取測試視頻域名,而最終視頻的卡頓率也有所優化,在弱網場景則更加明顯。
由于切量到 QUIC 測試,視頻域名需要同步從 HTTP 切換到 HTTPS,這樣會增加 QUIC 測試干擾項,為了更好地觀察數據,我們設計了 QUIC 的兩套切量策略,保持一部分原有域名的請求,并將又一部分原有域名也切換到 HTTPS,而 QUIC 測試將另一部分原有域名切換為 CDN 域名進行測試,切量控制如 圖8 所示。
圖8 QUIC動態配置
而由于 QUIC 存在較高的未知性,切換網絡庫對于大量級的網易新聞來說,存在的風險較高,而產生異常對用戶影響也極大,所以 Team 采取了 CDN 先預熱,后動態下發配置,篩選目標用戶進行逐步放量的模式,歷經三個版本,完成 QUIC 的測試。
3.2 項目里程
QUIC 立項前開始零零散散的一段調研期,而后4月中旬接入,各方1周完成敏捷開發,以 MVP 最小可行性原則快速完成功能開發,后續聯調、上線測試和逐步迭代改進,持續共計 3 個月左右,以團隊預期的速度穩定探索,最終取得了較為理想的測試效果。
數據表現
4.1 平均響應時間與錯誤率
通過全鏈路上報的信息,可以很直觀的導出 QUIC 與原有請求傳輸方式的對比信息,通過放量控制,同一 Host 下,我們使 QUIC 協議請求量與 H2 對齊,其 Count 曲線如 圖9 所示。
(以下圖中,藍色皆為H2曲線,黃色皆為QUIC曲線)
圖9 請求量對比
得出的 QUIC 與 H2 平均響應時間對比如 圖10 所示,可以直觀的看到,QUIC 平均響應時間較 H2 縮減了約 45%。
圖10 平均響應時間對比
而 QUIC 帶來的錯誤率也大幅降低,在錯誤率表現上同樣優秀,如 圖11 所示。
圖11 錯誤率對比
4.2 弱網表現
基于業界的部分研究結論,我們對 QUIC 在弱網的表現也進行了監控。
這里的網絡情況以獲取到的 手機網絡信號強度 LTE 等級 為依據,如下數據觀測基于網絡信號強度劃分的 6 個等級,其中:
- 0、1、2 這三級代表弱網情況;
- 4、5 這兩級代表一般網絡情況。
4.2.1 平均響應時間
同樣保持請求量對齊,在該數據觀測定義的弱網場景下,QUIC 與 H2 的平均響應時間對比曲線如 圖12 所示。
(以下圖中,藍色皆為H2曲線,黃色皆為QUIC曲線)
圖12 弱網場景下RT
在該數據觀測定義的一般網絡場景下,QUIC 與 H2 的平均響應時間對比曲線如 圖13 所示。
圖13 一般網絡場景下RT
從弱網場景統計曲線的更大差值,可以粗略得出結論,QUIC 在弱網場景下,請求響應時間優化更明顯。
4.2.2 錯誤率
在該數據觀測定義的弱網場景下,QUIC 與 H2 的錯誤率對比曲線如 圖14 所示。
圖14 弱網場景下錯誤率
在該數據觀測定義的一般網絡場景下,QUIC 與 H2 的錯誤率對比曲線如 圖15 所示。
圖15 一般網絡場景下錯誤率
從弱網場景統計曲線的更大差值,同樣可以粗略得出結論,QUIC 在弱網場景下,錯誤率優化更明顯。
4.3 視頻性能
在視頻性能方面,我們分別針對卡頓率和1秒率進行了監控。
4.3.1 卡頓率
從 圖16 可見,QUIC 在視頻性能表現上,相比 H2 請求,卡頓率下降約為25%+。
(以下圖中,藍色皆為H2曲線,黃色皆為QUIC曲線)
圖16 視頻卡頓率
4.3.2 1秒率
這里的 1秒率 是指視頻在1秒內達到播放狀態的比例,從 圖17 可見,QUIC 在1秒率表現上,相比 H2 請求有一定幅度提升。
圖17 視頻1秒率
后續展望
對于在 Cronet 的定制和處理方面,還有更多的改進空間,如協商過程的優化,DNS 的定制優化處理等,后續我們會逐步精進,繼續深入挖掘 QUIC,期待發現更多的驚喜。
作者簡介
李云鵬 2016年加入網易傳媒,目前主要負責架構和性能優化相關工作。QCon 大會講師,著有《移動開發架構設計實戰》等書籍。
李鑫飛 網易新聞客戶端 iOS 架構組組長,負責客戶端基礎架構,組件化及性能優化等工作。
張 鑫 網易資深應用運維工程師,負責網易新聞內容發布系統運維工作,在內容發布、流媒體點播、直播、CDN運維、全鏈路監控、大數據運維、業務容器化方面有豐富運維經驗。
鳴謝
發起人與項目組其他成員;
項目發起人:技術總監 棉明;
Android:技術專家 廣叢;
iOS:資深工程師 龐博;
運維及杭研團隊等。






