QUIC協議原理分析

本文主要介紹 QUIC 協議產生的背景和核心特性。

QUIC 概述

Quic 全稱 quick udp internet connection [1],“快速 UDP 互聯網連接”,(和英文 quick 諧音,簡稱“快”)是由 google 提出的使用 udp 進行多路併發傳輸的協議。

Quic 相比現在廣泛應用的 http2+tcp+tls 協議有如下優勢 [2]:

  1. 減少了 TCP 三次握手及 TLS 握手時間。

  2. 改進的擁塞控制。

  3. 避免隊頭阻塞的多路複用。

  4. 連接遷移。

  5. 前向冗餘糾錯。

爲什麼需要 QUIC

從上個世紀 90 年代互聯網開始興起一直到現在,大部分的互聯網流量傳輸只使用了幾個網絡協議。使用 IPv4 進行路由,使用 TCP 進行連接層面的流量控制,使用 SSL/TLS 協議實現傳輸安全,使用 DNS 進行域名解析,使用 HTTP 進行應用數據的傳輸。

而且近三十年來,這幾個協議的發展都非常緩慢。TCP 主要是擁塞控制算法的改進,SSL/TLS 基本上停留在原地,幾個小版本的改動主要是密碼套件的升級,TLS1.3[3] 是一個飛躍式的變化,但截止到今天,還沒有正式發佈。IPv4 雖然有一個大的進步,實現了 IPv6,DNS 也增加了一個安全的 DNSSEC,但和 IPv6 一樣,部署進度較慢。

隨着移動互聯網快速發展以及物聯網的逐步興起,網絡交互的場景越來越豐富,網絡傳輸的內容也越來越龐大,用戶對網絡傳輸效率和 WEB 響應速度的要求也越來越高。

一方面是歷史悠久使用廣泛的古老協議,另外一方面用戶的使用場景對傳輸性能的要求又越來越高。如下幾個由來已久的問題和矛盾就變得越來越突出。

  1. 協議歷史悠久導致中間設備僵化。

  2. 依賴於操作系統的實現導致協議本身僵化。

  3. 建立連接的握手延遲大。

  4. 隊頭阻塞。

這裏分小節簡單說明一下:

中間設備的僵化

可能是 TCP 協議使用得太久,也非常可靠。所以我們很多中間設備,包括防火牆、NAT 網關,整流器等出現了一些約定俗成的動作。

比如有些防火牆只允許通過 80 和 443,不放通其他端口。NAT 網關在轉換網絡地址時重寫傳輸層的頭部,有可能導致雙方無法使用新的傳輸格式。整流器和中間代理有時候出於安全的需要,會刪除一些它們不認識的選項字段。

TCP 協議本來是支持端口、選項及特性的增加和修改。但是由於 TCP 協議和知名端口及選項使用的歷史太悠久,中間設備已經依賴於這些潛規則,所以對這些內容的修改很容易遭到中間環節的干擾而失敗。

而這些干擾,也導致很多在 TCP 協議上的優化變得小心謹慎,步履維艱。

依賴於操作系統的實現導致協議僵化

TCP 是由操作系統在內核西方棧層面實現的,應用程序只能使用,不能直接修改。雖然應用程序的更新迭代非常快速和簡單。但是 TCP 的迭代卻非常緩慢,原因就是操作系統升級很麻煩。

現在移動終端更加流行,但是移動端部分用戶的操作系統升級依然可能滯後數年時間。PC 端的系統升級滯後得更加嚴重,windows xp 現在還有大量用戶在使用,儘管它已經存在快 20 年。

服務端系統不依賴用戶升級,但是由於操作系統升級涉及到底層軟件和運行庫的更新,所以也比較保守和緩慢。

這也就意味着即使 TCP 有比較好的特性更新,也很難快速推廣。比如 TCP Fast Open。它雖然 2013 年就被提出了,但是 Windows 很多系統版本依然不支持它。

建立連接的握手延遲大

不管是 HTTP1.0/1.1 還是 HTTPS,HTTP2,都使用了 TCP 進行傳輸。HTTPS 和 HTTP2 還需要使用 TLS 協議來進行安全傳輸。這就出現了兩個握手延遲:

1.TCP 三次握手導致的 TCP 連接建立的延遲。

2.TLS 完全握手需要至少 2 個 RTT 才能建立,簡化握手需要 1 個 RTT 的握手延遲。

對於很多短連接場景,這樣的握手延遲影響很大,且無法消除。

隊頭阻塞

隊頭阻塞主要是 TCP 協議的可靠性機制引入的。TCP 使用序列號來標識數據的順序,數據必須按照順序處理,如果前面的數據丟失,後面的數據就算到達了也不會通知應用層來處理。

另外 TLS 協議層面也有一個隊頭阻塞,因爲 TLS 協議都是按照 record 來處理數據的,如果一個 record 中丟失了數據,也會導致整個 record 無法正確處理。

概括來講,TCP 和 TLS1.2 之前的協議存在着結構性的問題,如果繼續在現有的 TCP、TLS 協議之上實現一個全新的應用層協議,依賴於操作系統、中間設備還有用戶的支持。部署成本非常高,阻力非常大。

所以 QUIC 協議選擇了 UDP,因爲 UDP 本身沒有連接的概念,不需要三次握手,優化了連接建立的握手延遲,同時在應用程序層面實現了 TCP 的可靠性,TLS 的安全性和 HTTP2 的併發性,只需要用戶端和服務端的應用程序支持 QUIC 協議,完全避開了操作系統和中間設備的限制。

QUIC 核心特性

連接建立延時低

0RTT 建連可以說是 QUIC 相比 HTTP2 最大的性能優勢。那什麼是 0RTT 建連呢?這裏面有兩層含義。

  1. 傳輸層 0RTT 就能建立連接。

  2. 加密層 0RTT 就能建立加密連接。

 

圖 1 HTTPS 及 QUIC 建連過程

比如上圖左邊是 HTTPS 的一次完全握手的建連過程,需要 3 個 RTT。就算是 Session Resumption[14],也需要至少 2 個 RTT。

而 QUIC 呢?由於建立在 UDP 的基礎上,同時又實現了 0RTT 的安全握手,所以在大部分情況下,只需要 0 個 RTT 就能實現數據發送,在實現前向加密 [15] 的基礎上,並且 0RTT 的成功率相比 TLS 的 Sesison Ticket[13] 要高很多。

改進的擁塞控制

TCP 的擁塞控制實際上包含了四個算法:慢啓動,擁塞避免,快速重傳,快速恢復 [22]。

QUIC 協議當前默認使用了 TCP 協議的 Cubic 擁塞控制算法 [6],同時也支持 CubicBytes, Reno, RenoBytes, BBR, PCC 等擁塞控制算法。

從擁塞算法本身來看,QUIC 只是按照 TCP 協議重新實現了一遍,那麼 QUIC 協議到底改進在哪些方面呢?主要有如下幾點:

 可插拔

什麼叫可插拔呢?就是能夠非常靈活地生效,變更和停止。體現在如下方面:

  1. 應用程序層面就能實現不同的擁塞控制算法,不需要操作系統,不需要內核支持。這是一個飛躍,因爲傳統的 TCP 擁塞控制,必須要端到端的網絡協議棧支持,才能實現控制效果。而內核和操作系統的部署成本非常高,升級週期很長,這在產品快速迭代,網絡爆炸式增長的今天,顯然有點滿足不了需求。

  2. 即使是單個應用程序的不同連接也能支持配置不同的擁塞控制。就算是一臺服務器,接入的用戶網絡環境也千差萬別,結合大數據及人工智能處理,我們能爲各個用戶提供不同的但又更加精準更加有效的擁塞控制。比如 BBR 適合,Cubic 適合。

  3. 應用程序不需要停機和升級就能實現擁塞控制的變更,我們在服務端只需要修改一下配置,reload 一下,完全不需要停止服務就能實現擁塞控制的切換。

STGW 在配置層面進行了優化,我們可以針對不同業務,不同網絡制式,甚至不同的 RTT,使用不同的擁塞控制算法。

 單調遞增的 Packet Number

TCP 爲了保證可靠性,使用了基於字節序號的 Sequence Number 及 Ack 來確認消息的有序到達。

QUIC 同樣是一個可靠的協議,它使用 Packet Number 代替了 TCP 的 sequence number,並且每個 Packet Number 都嚴格遞增,也就是說就算 Packet N 丟失了,重傳的 Packet N 的 Packet Number 已經不是 N,而是一個比 N 大的值。而 TCP 呢,重傳 segment 的 sequence number 和原始的 segment 的 Sequence Number 保持不變,也正是由於這個特性,引入了 Tcp 重傳的歧義問題。

 

圖 2 Tcp 重傳歧義性

如上圖所示,超時事件 RTO 發生後,客戶端發起重傳,然後接收到了 Ack 數據。由於序列號一樣,這個 Ack 數據到底是原始請求的響應還是重傳請求的響應呢?不好判斷。

如果算成原始請求的響應,但實際上是重傳請求的響應(上圖左),會導致採樣 RTT 變大。如果算成重傳請求的響應,但實際上是原始請求的響應,又很容易導致採樣 RTT 過小。

由於 Quic 重傳的 Packet 和原始 Packet 的 Pakcet Number 是嚴格遞增的,所以很容易就解決了這個問題。

 

圖 3 Quic 重傳沒有歧義性

如上圖所示,RTO 發生後,根據重傳的 Packet Number 就能確定精確的 RTT 計算。如果 Ack 的 Packet Number 是 N+M,就根據重傳請求計算採樣 RTT。如果 Ack 的 Pakcet Number 是 N,就根據原始請求的時間計算採樣 RTT,沒有歧義性。

但是單純依靠嚴格遞增的 Packet Number 肯定是無法保證數據的順序性和可靠性。QUIC 又引入了一個 Stream Offset 的概念。

即一個 Stream 可以經過多個 Packet 傳輸,Packet Number 嚴格遞增,沒有依賴。但是 Packet 裏的 Payload 如果是 Stream 的話,就需要依靠 Stream 的 Offset 來保證應用數據的順序。如錯誤! 未找到引用源。所示,發送端先後發送了 Pakcet N 和 Pakcet N+1,Stream 的 Offset 分別是 x 和 x+y。

假設 Packet N 丟失了,發起重傳,重傳的 Packet Number 是 N+2,但是它的 Stream 的 Offset 依然是 x,這樣就算 Packet N + 2 是後到的,依然可以將 Stream x 和 Stream x+y 按照順序組織起來,交給應用程序處理。

 

圖 4 Stream Offset 保證有序性

 不允許 Reneging

什麼叫 Reneging 呢?就是接收方丟棄已經接收並且上報給 SACK 選項的內容 [8]。TCP 協議不鼓勵這種行爲,但是協議層面允許這樣的行爲。主要是考慮到服務器資源有限,比如 Buffer 溢出,內存不夠等情況。

Reneging 對數據重傳會產生很大的干擾。因爲 Sack 都已經表明接收到了,但是接收端事實上丟棄了該數據。

QUIC 在協議層面禁止 Reneging,一個 Packet 只要被 Ack,就認爲它一定被正確接收,減少了這種干擾。

 更多的 Ack 塊

TCP 的 Sack 選項能夠告訴發送方已經接收到的連續 Segment 的範圍,方便發送方進行選擇性重傳。

由於 TCP 頭部最大隻有 60 個字節,標準頭部佔用了 20 字節,所以 Tcp Option 最大長度只有 40 字節,再加上 Tcp Timestamp option 佔用了 10 個字節 [25],所以留給 Sack 選項的只有 30 個字節。

每一個 Sack Block 的長度是 8 個,加上 Sack Option 頭部 2 個字節,也就意味着 Tcp Sack Option 最大隻能提供 3 個 Block。

但是 Quic Ack Frame 可以同時提供 256 個 Ack Block,在丟包率比較高的網絡下,更多的 Sack Block 可以提升網絡的恢復速度,減少重傳量。

 Ack Delay 時間

Tcp 的 Timestamp 選項存在一個問題 [25],它只是回顯了發送方的時間戳,但是沒有計算接收端接收到 segment 到發送 Ack 該 segment 的時間。這個時間可以簡稱爲 Ack Delay。

這樣就會導致 RTT 計算誤差。如下圖:

 

可以認爲 TCP 的 RTT 計算:

而 Quic 計算如下:

當然 RTT 的具體計算沒有這麼簡單,需要採樣,參考歷史數值進行平滑計算,參考如下公式 [9]。

基於 stream 和 connecton 級別的流量控制

QUIC 的流量控制 [22] 類似 HTTP2,即在 Connection 和 Stream 級別提供了兩種流量控制。爲什麼需要兩類流量控制呢?主要是因爲 QUIC 支持多路複用。

  1. Stream 可以認爲就是一條 HTTP 請求。

  2. Connection 可以類比一條 TCP 連接。多路複用意味着在一條 Connetion 上會同時存在多條 Stream。既需要對單個 Stream 進行控制,又需要針對所有 Stream 進行總體控制。

QUIC 實現流量控制的原理比較簡單:

通過 window_update 幀告訴對端自己可以接收的字節數,這樣發送方就不會發送超過這個數量的數據。

通過 BlockFrame 告訴對端由於流量控制被阻塞了,無法發送數據。

QUIC 的流量控制和 TCP 有點區別,TCP 爲了保證可靠性,窗口左邊沿向右滑動時的長度取決於已經確認的字節數。如果中間出現丟包,就算接收到了更大序號的 Segment,窗口也無法超過這個序列號。

但 QUIC 不同,就算此前有些 packet 沒有接收到,它的滑動只取決於接收到的最大偏移字節數。

 

圖 5 Quic Flow Control

針對 Stream:

針對 Connection:

同樣地,STGW 也在連接和 Stream 級別設置了不同的窗口數。

最重要的是,我們可以在內存不足或者上游處理性能出現問題時,通過流量控制來限制傳輸速率,保障服務可用性。

沒有隊頭阻塞的多路複用

QUIC 的多路複用和 HTTP2 類似。在一條 QUIC 連接上可以併發發送多個 HTTP 請求 (stream)。但是 QUIC 的多路複用相比 HTTP2 有一個很大的優勢。

QUIC 一個連接上的多個 stream 之間沒有依賴。這樣假如 stream2 丟了一個 udp packet,也只會影響 stream2 的處理。不會影響 stream2 之前及之後的 stream 的處理。

這也就在很大程度上緩解甚至消除了隊頭阻塞的影響。

多路複用是 HTTP2 最強大的特性 [7],能夠將多條請求在一條 TCP 連接上同時發出去。但也惡化了 TCP 的一個問題,隊頭阻塞 [11],如下圖示:

 

圖 6 HTTP2 隊頭阻塞

HTTP2 在一個 TCP 連接上同時發送 4 個 Stream。其中 Stream1 已經正確到達,並被應用層讀取。但是 Stream2 的第三個 tcp  segment 丟失了,TCP 爲了保證數據的可靠性,需要發送端重傳第 3 個 segment 才能通知應用層讀取接下去的數據,雖然這個時候 Stream3 和 Stream4 的全部數據已經到達了接收端,但都被阻塞住了。

不僅如此,由於 HTTP2 強制使用 TLS,還存在一個 TLS 協議層面的隊頭阻塞 [12]。

 

圖 7 TLS 隊頭阻塞

Record 是 TLS 協議處理的最小單位,最大不能超過 16K,一些服務器比如 Nginx 默認的大小就是 16K。由於一個 record 必須經過數據一致性校驗才能進行加解密,所以一個 16K 的 record,就算丟了一個字節,也會導致已經接收到的 15.99K 數據無法處理,因爲它不完整。

那 QUIC 多路複用爲什麼能避免上述問題呢?

  1. QUIC 最基本的傳輸單元是 Packet,不會超過 MTU 的大小,整個加密和認證過程都是基於 Packet 的,不會跨越多個 Packet。這樣就能避免 TLS 協議存在的隊頭阻塞。

  2. Stream 之間相互獨立,比如 Stream2 丟了一個 Pakcet,不會影響 Stream3 和 Stream4。不存在 TCP 隊頭阻塞。

 

圖 8 QUIC 多路複用時沒有隊頭阻塞的問題

當然,並不是所有的 QUIC 數據都不會受到隊頭阻塞的影響,比如 QUIC 當前也是使用 Hpack 壓縮算法 [10],由於算法的限制,丟失一個頭部數據時,可能遇到隊頭阻塞。

總體來說,QUIC 在傳輸大量數據時,比如視頻,受到隊頭阻塞的影響很小。

加密認證的報文

TCP 協議頭部沒有經過任何加密和認證,所以在傳輸過程中很容易被中間網絡設備篡改,注入和竊聽。比如修改序列號、滑動窗口。這些行爲有可能是出於性能優化,也有可能是主動攻擊。

但是 QUIC 的 packet 可以說是武裝到了牙齒。除了個別報文比如 PUBLIC_RESET 和 CHLO,所有報文頭部都是經過認證的,報文 Body 都是經過加密的。

這樣只要對 QUIC 報文任何修改,接收端都能夠及時發現,有效地降低了安全風險。

如下圖所示,紅色部分是 Stream Frame 的報文頭部,有認證。綠色部分是報文內容,全部經過加密。

 

連接遷移

一條 TCP 連接 [17] 是由四元組標識的(源 IP,源端口,目的 IP,目的端口)。什麼叫連接遷移呢?就是當其中任何一個元素髮生變化時,這條連接依然維持着,能夠保持業務邏輯不中斷。當然這裏面主要關注的是客戶端的變化,因爲客戶端不可控並且網絡環境經常發生變化,而服務端的 IP 和端口一般都是固定的。

比如大家使用手機在 WIFI 和 4G 移動網絡切換時,客戶端的 IP 肯定會發生變化,需要重新建立和服務端的 TCP 連接。

又比如大家使用公共 NAT 出口時,有些連接競爭時需要重新綁定端口,導致客戶端的端口發生變化,同樣需要重新建立 TCP 連接。

針對 TCP 的連接變化,MPTCP[5] 其實已經有了解決方案,但是由於 MPTCP 需要操作系統及網絡協議棧支持,部署阻力非常大,目前並不適用。

所以從 TCP 連接的角度來講,這個問題是無解的。

那 QUIC 是如何做到連接遷移呢?很簡單,任何一條 QUIC 連接不再以 IP 及端口四元組標識,而是以一個 64 位的隨機數作爲 ID 來標識,這樣就算 IP 或者端口發生變化時,只要 ID 不變,這條連接依然維持着,上層業務邏輯感知不到變化,不會中斷,也就不需要重連。

由於這個 ID 是客戶端隨機產生的,並且長度有 64 位,所以衝突概率非常低。

其他亮點

此外,QUIC 還能實現前向冗餘糾錯,在重要的包比如握手消息發生丟失時,能夠根據冗餘信息還原出握手消息。

QUIC 還能實現證書壓縮,減少證書傳輸量,針對包頭進行驗證等。

 

原文鏈接: https://mp.weixin.qq.com/s?__biz=MzI4MTY0NTk4MQ==&mid=2247484085&idx=4&sn=abe60fd802e824c806df008901937f3f&chksm=eba74447dcd0cd51bf1066e72ed584ad8f376b71315e0cd1cc55133cd2c8dfce83d7eb8d28da&mpshare=1&scene=1&srcid=1105IfWV6lbxZbRkrN8Wm7Dh#rd

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章