TCP 被 HTTP-3 拋棄了!

大家好,我是小林。

從 HTTP/1.1 到 HTTP/2,HTTP 協議一直都是使用 TCP 作爲傳輸協議。

然而,就在最新的 HTTP/3,HTTP 就直接把 TCP 拋棄了,向孤立無援的 UDP 伸出了援手,基於 UDP 協議的基礎上,在應用層實現了一個可靠的傳輸協議 —— QUIC。

很多同學可能就好奇了,HTTP 都用 TCP 都用了幾十年了,而且 TCP 已經是那麼完善的可靠傳輸協議了,又有超時重傳、按序接收、流量控制、擁塞控制這些特性,怎麼突然就把 TCP 拋棄了?到底是 TCP 哪裏做的不夠好?是不是雞蛋裏挑骨頭了?

所以,今天就跟大家聊聊,TCP 那些不夠 “好” 的原因。

TCP 存在隊頭阻塞問題

TCP 隊頭阻塞的問題要從兩個角度看,一個是發送窗口的隊頭阻塞,另外一個是接收窗口的隊頭阻塞

1、發送窗口的隊頭阻塞。

TCP 發送出去的數據,都是需要按序確認的,只有在數據都被按順序確認完後,發送窗口才會往前滑動。舉個例子,比如下圖的發送方把發送窗口內的數據全部都發出去了,可用窗口的大小就爲 0 了,表明可用窗口耗盡,在沒收到 ACK 確認之前是無法繼續發送數據了。

接着,當發送方收到對第 32~36 字節的 ACK 確認應答後,則滑動窗口往右邊移動 5 個字節,因爲有 5 個字節的數據被應答確認,接下來第 52~56 字節又變成了可用窗口,那麼後續也就可以發送 52~56 這 5 個字節的數據了。

但是如果某個數據報文丟失或者其對應的 ACK 報文在網絡中丟失,會導致發送方無法移動發送窗口,這時就無法再發送新的數據,只能超時重傳這個數據報文,直到收到這個重傳報文的 ACK,發送窗口才會移動,繼續後面的發送行爲。

舉個例子,比如下圖,客戶端是發送方,服務器是接收方。

客戶端發送了第 5~9 字節的數據,但是第 5 字節的 ACK 確認報文在網絡中丟失了,那麼即使客戶端收到第 6~9 字節的 ACK 確認報文,發送窗口也不會往前移動。

此時的第 5 字節相當於 “隊頭”,因爲沒有收到“隊頭” 的 ACK 確認報文,導致發送窗口無法往前移動,此時發送方就無法繼續發送後面的數據,相當於按下了發送行爲的暫停鍵,這就是發送窗口的隊頭阻塞問題

2、接收窗口的隊頭阻塞。

接收方收到的數據範圍必須在接收窗口範圍內,如果收到超過接收窗口範圍的數據,就會丟棄該數據,比如下圖接收窗口的範圍是 32 ~ 51 字節,如果收到第 52 字節以上數據都會被丟棄。

接收窗口什麼時候才能滑動?當接收窗口收到有序數據時,接收窗口才能往前滑動,然後那些已經接收並且被確認的「有序」數據就可以被應用層讀取。

但是,當接收窗口收到的數據不是有序的,比如收到第 33~40 字節的數據,由於第 32 字節數據沒有收到, 接收窗口無法向前滑動,那麼即使先收到第 33~40 字節的數據,這些數據也無法被應用層讀取的。只有當發送方重傳了第 32 字節數據並且被接收方收到後,接收窗口才會往前滑動,然後應用層才能從內核讀取第 32~40 字節的數據。

好了,至此發送窗口和接收窗口的隊頭阻塞問題都說完了,這兩個問題的原因都是因爲 TCP 必須按序處理數據,也就是 TCP 層爲了保證數據的有序性,只有在處理完有序的數據後,滑動窗口才能往前滑動,否則就停留。

其實也不能怪 TCP 協議,它本來設計目的就是爲了保證數據的有序性。

HTTP/2 的隊頭阻塞

HTTP/2 通過抽象出 Stream 的概念,實現了 HTTP 併發傳輸,一個 Stream 就代表 HTTP/1.1 裏的請求和響應。

在 HTTP/2 連接上,不同 Stream 的幀是可以亂序發送的(因此可以併發不同的 Stream ),因爲每個幀的頭部會攜帶 Stream ID 信息,所以接收端可以通過 Stream ID 有序組裝成 HTTP 消息,而同一 Stream 內部的幀必須是嚴格有序的。

但是 HTTP/2 多個 Stream 請求都是在一條 TCP 連接上傳輸,這意味着多個 Stream 共用同一個 TCP 滑動窗口,那麼當發生數據丟失,滑動窗口是無法往前移動的,此時就會阻塞住所有的 HTTP 請求,這屬於 TCP 層隊頭阻塞

沒有隊頭阻塞的 QUIC

QUIC 也借鑑 HTTP/2 裏的 Stream 的概念,在一條 QUIC 連接上可以併發發送多個 HTTP 請求 (Stream)。

但是 QUIC 給每一個 Stream 都分配了一個獨立的滑動窗口,這樣使得一個連接上的多個 Stream 之間沒有依賴關係,都是相互獨立的,各自控制的滑動窗口

假如 Stream2 丟了一個 UDP 包,也只會影響 Stream2 的處理,不會影響其他 Stream,與 HTTP/2 不同,HTTP/2 只要某個流中的數據包丟失了,其他流也會因此受影響。

TCP 建立連接的延遲

對於 HTTP/1 和 HTTP/2 協議,TCP 和 TLS 是分層的,分別屬於內核實現的傳輸層、openssl 庫實現的表示層,因此它們難以合併在一起,需要分批次來握手,先 TCP 握手(1RTT),再 TLS 握手(2RTT),所以需要 3RTT 的延遲才能傳輸數據,就算 Session 會話服用,也需要至少 2 個 RTT,這在一定程序上增加了數據傳輸的延遲。

TCP 三次握手和 TLS 握手延遲,如圖:

HTTP/3 在傳輸數據前雖然需要 QUIC 協議握手,這個握手過程只需要 1 RTT,握手的目的是爲確認雙方的「連接 ID」,連接遷移就是基於連接 ID 實現的。

但是 HTTP/3 的 QUIC 協議並不是與 TLS 分層,因爲 QUIC 也是應用層實現的協議,所以可以將 QUIC 和 TLS 協議握手的過程合併在一起,QUIC 內部包含了 TLS,它在自己的幀會攜帶 TLS 裏的 “記錄”,再加上 QUIC 使用的是 TLS1.3,因此僅需 1 個 RTT 就可以「同時」完成建立連接與密鑰協商,甚至在第二次連接的時候,應用數據包可以和 QUIC 握手信息(連接信息 + TLS 信息)一起發送,達到 0-RTT 的效果。

如下圖右邊部分,HTTP/3 當會話恢復時,有效負載數據與第一個數據包一起發送,可以做到 0-RTT(下圖的右下角):

升級 TCP 的工作很困難

TCP 協議是誕生在 1973 年,至今 TCP 協議依然還在實現更多的新特性。

但是 TCP 協議是在內核中實現的,應用程序只能使用不能修改,如果要想升級 TCP 協議,那麼只能升級內核。

而升級內核這個工作是很麻煩的事情,麻煩的事情不是說升級內核這個操作很麻煩,而是由於內核升級涉及到底層軟件和運行庫的更新,我們的服務程序就需要回歸測試是否兼容新的內核版本,所以服務器的內核升級也比較保守和緩慢。

很多 TCP 協議的新特性,都是需要客戶端和服務端同時支持才能生效的,比如 TCP Fast Open 這個特性,雖然在 2013 年就被提出了,但是 Windows 很多系統版本依然不支持它,這是因爲 PC 端的系統升級滯後很嚴重,Windows Xp 現在還有大量用戶在使用,儘管它已經存在快 20 年。

所以,即使 TCP 有比較好的特性更新,也很難快速推廣,用戶往往要幾年或者十年才能體驗到。

相反,QUIC 是處於應用層的,所以如果升級 QUIC 協議的話,其實就是像升級軟件一樣輕鬆。而且,QUIC 可以針對不同的應用設置不同的擁塞控制算法,這樣靈活性就很高了,這是 TCP 做不到的,因爲 TCP 更改擁塞控制算法是對系統中所有應用都生效,無法根據不同應用設定不同的擁塞控制策略。

網絡遷移需要重新建立 TCP 連接

基於 TCP 傳輸協議的 HTTP 協議,由於是通過四元組(源 IP、源端口、目的 IP、目的端口)確定一條 TCP 連接。

那麼當移動設備的網絡從 4G 切換到 WIFI 時,意味着 IP 地址變化了,那麼就必須要斷開連接,然後重新建立 TCP 連接

而建立連接的過程包含 TCP 三次握手和 TLS 四次握手的時延,以及 TCP 慢啓動的減速過程,給用戶的感覺就是網絡突然卡頓了一下,因此連接的遷移成本是很高的。

QUIC 協議沒有用四元組的方式來 “綁定” 連接,而是通過連接 ID 來標記通信的兩個端點,客戶端和服務器可以各自選擇一組 ID 來標記自己,因此即使移動設備的網絡變化後,導致 IP 地址變化了,只要仍保有上下文信息(比如連接 ID、TLS 密鑰等),就可以 “無縫” 地複用原連接,消除重連的成本,沒有絲毫卡頓感,達到了連接遷移的功能。

總結

HTTP/3 拋棄 TCP 後,基於 UDP 實現的可靠傳輸 QUIC 協議,帶來這四點好處:

  1. 降低連接耗時:在客戶端有緩存的情況下實現 0-RTT 建立連接

  2. 更靈活的擁塞控制:在用戶態可以爲每個請求配置不同的擁塞控制策略

  3. 無隊頭阻塞的多路複用:每個請求流獨立擁有滑動窗口,互不影響

  4. 連接遷移:網絡切換不會中斷數據傳輸

不過, HTTP/3 也面臨了一些挑戰,QUIC 基於 UDP 協議在用戶空間實現的可靠傳輸協議,如果一些網絡設備無法識別出 QUIC 協議,那麼在這些網絡設備的眼裏它就是一個 UDP 協議。

而幾乎所有的電信運營商都會 “歧視” UDP 數據包,原因也很容易理解,畢竟歷史上幾次臭名昭著的 DDoS 攻擊都是基於 UDP 的。國內某城寬帶在某些區域更是直接禁止了非 53 端口的 UDP 數據包,而其他運營商即使沒有封禁 UDP,也是對 UDP 進行嚴格限流的。

自 2013 年 QUIC 被正式公開以來,到 2023 年已經發展了差不多 10 年,目前網上已經有了不少熱門開源的項目,除去帶頭大哥 Google 在完成了對自身搜索引擎的支持,還同時拉上了 Gmail 、YouTube 等站點。但對於國內的絕大部分站點來說,大部分還是 HTTP/2 協議,HTTP/3 之路,似乎還停留在東土大唐。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/zsM2iQUdk_YUaGhl-Z7CxQ