網易云信 QUIC 應用優化實踐
01 引言
QUIC 協議從傳輸層面相較 TCP 的幾點優勢:
- 0-RTT 建連QUIC 協議基于 UDP,本身無需握手,并且其使用 Diffie-Hellman 或者 ECC 算法,只在 1-RTT 就完成對等秘鑰的協商。QUIC 協議的 0-RTT 建連使用 TLS1.3,通過 early_data 完成加密數據透傳。
- 多路復用/無對頭阻塞相比于 HTTP/2 的多路復用,QUIC 不會受到隊頭阻塞的影響,各個流更獨立,多路復用的效果也更好。
- 連接遷移與 TC P 用四元組標識一個唯一連接不同,QUIC 使用一個 64 位的 ConnectionID 來標識連接,基于這個特點,QUIC 的使用連接遷移機制,在四元組發生變化時(比如客戶端從 WIFI 切換到蜂窩移動網絡),嘗試“保留”先前的連接,從而維持數據傳輸不中斷。
- 可定制的擁塞控制QUIC 協議沒有定義擁 塞控制算法的使用,這部分實現在應用層,方便開發者自行優化迭代。
02 QUIC 協議從協議層面相較 TCP 的幾點差別
- Separate Packet Number SpacesQUIC 協議定義了 4 種不同的加密級別,各種加密級別使用不同包序列號空間。
- Monotonically Increasing Packet Numbers相同包序列號空間中的包序列號單調遞增,避免了重傳歧義。 QUIC 協議的包序列號空間只標識傳輸順序,數據包內容的順序則用 STR EAM 幀當中的偏移(offset)來標識。
- Clearer Loss Epoch當一個 QUIC 包被申明為丟失,QUIC 開啟一段丟失檢測的周期,在此之后發送的任何一個 QUIC 包被確認則刷新檢測周期的時間。 與 TCP 不同,TCP 會一直等待序列號空間中的空白被填滿盡管有可能在傳輸過程中相同數據包發生了多次丟失。 這樣做的意義在于:QUIC 可以更精確地在每個往返時間(RTT)內去更新擁塞窗口的大小。
- No Reneging不能食言。一旦一個包被對端確認,則改包不能再被申明為丟失。這樣的設定大大簡化了雙端傳輸協議的設計,也減小了發送端的內存壓力。
- More ACK Ranges相比 TCP 的 SACK 只能確認三個段(范圍),QUIC 協議的 ACK 幀支持更多的段(范圍)確認。 在高丟包場景下,加快了重傳恢復的速度,避免零散的范圍確認導致的傳輸中斷。
- Explicit Correction For Delayed AcknowledgementsQUIC 協議將計算從接收包到發送該包 ACK 之間的延遲時間,并顯式寫入 ACK 幀中。 這樣的設定旨在更加精準地計算網路的往返時間。
- Probe Timeout Replaces RTO and TLPQUIC 協議使用 PTO(probe timeout)探測超時機制,包含了對端的期望最大確認延時,而不是一個固定的最小超時。 與 TCP 的 RTO 超時不同的是,QUIC 協議在 PTO 過期時不會去嘗試折疊擁塞窗口,因為尾部數據的丟失并不能表示網路發生了持續的擁塞。 發送方可以不受限制地發送更多的數據包在其還有剩余的擁塞窗口的條件下,即便此時已經發生了 PTO 超時。 相對于 TCP 的 RTO 機制,PTO 機制更加激進。
- The Minimum Congestion Window is Two PacketsTCP 使用一個數據包作為最小擁塞窗口,如果這個數據包丟失了,意味著需要等待 RTO 來進行重傳,這很可能遠遠大于一個往返時間(RTT),QUIC 協議建議使用兩個數據包作為最小擁塞窗口,雖然這樣做會增加流量,但是被認為是安全的。
03 QUIC 協議在網易云信的應用
在網易云信音視頻服務的架構中,信令用于 SDP 的交互 、 會話房間的創建 與管理 、 用戶信息的上傳與下發 等,其傳輸的穩定性和及時性至關重要。傳統的 WEBRTC 建議使用 WebSocket 作為信令傳輸協議,受限于 TCP 協議的缺陷,其在建連時間、傳輸效率和弱網抗性方面的效果不盡人意。而這些問題直接影響到音視頻服務的基線指標,比如首幀時間、鏈路的穩定性以及弱網抗性等。
云信 QUIC 加速服務設計:
網易云信使用 QUIC 協議替代 WebSocket 協議進行信令的傳輸,并在應用和協議層面做了若干優化實踐:
- 多路復用: 根據不同信令的特性,給請求分類分級。對于 Request/Reponse 類型的消息,其可靠性和實時性的要求最高,使用高優先級的 STREAM 進行傳輸。對于用于鏈路保活的心跳消息,則使用較低優先級的 STREAM 進行傳輸。
- 不可靠的傳輸拓展: 有一類 Notify 消息類型,不需要接收端進行回復,往往用于廣播各端用戶的網絡狀態或者其他信息。其對于實時性的要求很高,但是對可靠性沒有很高的要求。對于這種信令,我們可以使用 QUIC 協議的不可靠傳輸特性進行傳輸。這種特殊的傳輸使用一種 DATAGRAM 幀,傳輸這種特殊的幀,需要在 Initial 包中的 CH 模塊的 QUIC 傳輸參數表中進行申明(name=max_datagram_frame_size, value=0x20),用以通告對端對于 DATAGRAM 幀的支持。max_datagram_frame_size 傳輸參數是一個整數值(表示為可變長度整數),表示端點愿意接收的 DATAGRAM 幀的最大大小(包括幀類型、長度和有效負載),以字節為單位。DATAGRAM 幀用于以不可靠的方式傳輸應用程序數據。幀中的 Type 字段采用 0b0011000X 的形式(或值 0x30 和 0x31),最低有效位是 LEN 位(0x01),表示是否存在 Length 字段:如果該位設置為 0,則 Length 字段不存在,Datagram Data 字段擴展到數據包的結尾;如果該位設置為 1,則存在長度字段。 DATAGRAM 幀的結構如下:
盡 管 DATAGRAM 幀在檢測到丟失時不會進行重傳,但也是需要被 ack 的。
- 報文壓縮: 云信在傳輸層引入了 Deflate 算法對 STREAM 幀進行壓縮,旨在降低信令傳輸的帶寬占用。
- 動態的冗余策略: 因為信令非流式數據,FEC 并不能適用于斷續數據的傳輸,以 RTT 和丟包率等指標動態地增加冗余保護對提升傳輸的弱網抗性也有相當積極的作用。
04 云信 QUIC 的弱網表現
首屏耗時和登錄耗時
上圖是云信音視頻業務信令建連使用 TCP 和 QUIC 的對比。在 首幀耗時 的指標上,QUIC 有 20% 的提升。在 登錄耗時 的指標上,QUIC 有接近 30% 的提升。主要的原因是 QUIC 的建連對比 TCP+TLS 有 2~3 個 RTT 的優化,在高 RTT 的場景下握手時間縮短尤為明顯。在直播場景下,云信 QUIC 做了私有化的 0RTT 握手的優化,建連更加快速。
抗丟包性
上圖是云信信令數據在 QUIC 和 TCP 鏈路下能夠抗住的最大丟包率。QUIC 在上行丟包率達到 70% 的條件下仍然可以提供服務,下行邊界甚至可以抗住 75% 的丟包。TCP 鏈路在 45% 的丟包情況下就會出現斷開重連。相對于 TCP 的信令鏈路 QUIC 鏈路有 50% 的提升。
主要原因:
- 云信實現了動態冗余,會檢測到丟包之后增加冗余度,這樣就用冗余包彌補了高丟包,帶來了抗丟包性能。
- QUIC 改進的流量控制和擁塞控制算法讓 QUIC 在弱網絡下可能取得更大的傳輸優勢。
帶限
我們還做了在帶寬受限的情況下,QUIC 對于帶寬的使用率,基本上 QUIC 對于帶寬的使用率都能達到 90% 以上,然而 TCP 就要差很多。
05展望&總結
網易云信在可靠數據加速上可靠數據傳輸上已經得到很大的提升,但是仍然還有一些需要優化的地方:一旦單向發生丟包,會引起服務器和端都增加雙向的冗余度,帶來不必要的冗余增加。后續會檢測到單向丟包,只針對丟包的鏈路進行冗余度增加。對于高 RTT 和高丟包場景,QUIC 擁塞控制算法需要持續優化。 網易云信將持續在音視頻領域,在各種極端情況下為用戶提供優質的服務。
作者介紹
董相成,網易云信資深音視頻引擎開發工程師,負責網易云信低延遲直播業務和音視頻媒體引擎開發,在音視頻數據傳輸和網絡數據轉發方面有著豐富的經驗。