說一下 HTTP-3 新特性,爲什麼選擇使用 UDP 協議?

引言

本文主要分爲以下幾個方面循序漸進走進 HTTP/3:

HTTP/2 和 TCP 的缺陷

HTTP/2 使用二進制傳輸、Header 壓縮(HPACK)、多路複用等,相較於 HTTP/1.1 大幅提高了數據傳輸效率,但它仍然存在着以下幾個致命問題(主要由底層支撐的 TCP 協議造成):

1. 建立連接時間長

RTT 往返時間

如何定義建立連接時間喃?這裏引入一個概念:RTT(Round-Trip Time),往返時間,表示從發送端發送數據開始,到發送端收到來自接收端的確認(接收端收到數據後便立即發送確認,不包含數據傳輸時間)總共經歷的時間,即通信一來一回的時間

TCP 建立連接時間

TCP 通過三次揮手建立了 TCP 虛擬通道,它總共需要花費:

相當於一個半來回,故 TCP 建立連接時間 = 1.5 RTT

HTTP 交易時間

客戶端在請求數據的時候,首先花費 1.5 RTT 建立 TCP 連接,然後 TCP 纔開始傳輸 HTTP 請求,瀏覽器收到服務器的響應,又要等待的時間爲:

故 HTTP 交易時間 = 1 RTT

由於 TCP 在第三次握手的時候,不需要等待服務器端的響應,所以節省 0.5 RTT,那麼基於 TCP 傳輸的 HTTP 通信,一共花費的時間總和:

HTTP 通信時間總和 = TCP 建立連接時間 + HTTP 交易時間 = 1 RTT + 1 RTT = 2 RTT

HTTPS 通信時間

HTTP/2 延續了 HTTP/1 的 “明文” 特點,可以像以前一樣使用明文傳輸數據,不強制使用加密通信,但 HTTPS 已經是大勢所趨,各大主流瀏覽器都公開宣佈只支持加密的 HTTP/2,所以,真實應用中的 HTTP/2 是還是加密的:

HTTPS 其實是 HTTP+SSL/TLS 的簡稱

所以,HTTPS 通信時間 = TCP 建立連接時間 +  TLS 連接時間 + HTTP 交易時間

TLS 連接時間

在 TLS 1.2 協議的握手,需要 2 個 RTT:

HTTPS 通信時間總和 = TCP 建立連接時間 + TLS 連接時間 + HTTP 交易時間 = 1 RTT + 2 RTT + 1 RTT = 4 RTT

如果服務器距離客戶端很近,RTT 時間較短 < 10ms,那麼 HTTPS 通信時間也不會超過 40 ms,用戶不會感知,但如果距離較遠,相隔上萬公里,一個 RTT 時間通常在 200ms 以上,那麼 HTTPS 通信將花費 800ms 甚至 1s 以上,這就嚴重影響到用戶體驗了

注意:在 TLS 1.3 協議中,首次建立連接只需要一個 RTT,後面恢復連接不需要 RTT 了

HTTPS 通信時間總和(基於 TLS1.2) = TCP 建立連接時間 + TLS1.2 連接時間 + HTTP 交易時間 = 1 RTT + 2 RTT + 1 RTT = 4 RTT

HTTPS 通信時間總和(基於 TLS1.3) = TCP 建立連接時間 + TLS1.3 連接時間 + HTTP 交易時間 = 1 RTT + 1 RTT + 1 RTT = 3 RTT

2. 隊頭阻塞問題相較於 HTTP/1.1 更嚴重

因爲 HTTP/2 使用了多路複用,一般來說同一域名下只需要使用一個 TCP 連接。當這個連接中出現了丟包的情況,那就會導致 HTTP/2 的表現情況反倒不如 HTTP/1 了。

因爲在出現丟包的情況下,整個 TCP 都要開始等待重傳,也就導致了後面的所有數據都被阻塞了。但是對於 HTTP/1 來說,可以開啓多個 TCP 連接,出現這種情況反到只會影響其中一個連接,剩餘的 TCP 連接還可以正常傳輸數據。

QUIC 協議爲什麼選擇 UDP

那麼可能就會有人考慮到去修改 TCP 協議,其實這已經是一件不可能完成的任務了。因爲 TCP 存在的時間實在太長,已經充斥在各種設備中,並且這個協議是由操作系統實現的,更新起來不大現實。

基於這個原因,Google 就更起爐竈搞了一個基於 UDP 協議的 QUIC 協議

谷歌這樣做看似出乎意料的,但我們對比一下 TCP 與 UDP 就會發現,這是很有道理的:

從上面的對比可以知道,谷歌要想從 TCP 上進行改造升級絕非易事,但是 UDP 雖然沒有 TCP 爲了保證可靠連接而引發的問題,但是 UDP 本身不可靠,又不能直接用。

所以,谷歌決定在 UDP 基礎上改造一個具備 TCP 協議優點的新協議也就順理成章了,這個新協議就是 QUIC 協議(Quick UDP Internet Connection),並且使用在了 HTTP/3 上,當然 HTTP/3 之前名爲 HTTP-over-QUIC,從這個名字中我們也可以發現,HTTP/3 最大的改造就是使用了 QUIC

QUIC 和 HTTP/3 新特性

QUIC 雖然基於 UDP,但是在原本的基礎上新增了很多功能,比如多路複用、0-RTT、使用 TLS1.3 加密、流量控制、有序交付、重傳等等功能。這裏我們就挑選幾個重要的功能學習下這個協議的內容。

1. 多路複用,解決隊頭阻塞問題

雖然 HTTP/2 支持了多路複用,但是 TCP 協議終究是沒有這個功能的。QUIC 原生就實現了這個功能

QUIC 協議是基於 UDP 協議實現的,同一個 QUIC 連接上可以創建多個 stream(數據流) 來發送多個 HTTP 請求,並且,多個 stream 之間沒有依賴,傳輸的單個 stream 可以保證有序交付且不會影響其他的數據流

例如下圖,stream2 丟了一個 UDP 包,不會影響後面跟着 Stream3 和 Stream4。這樣的技術就解決了之前 TCP 存在的隊頭阻塞問題。

並且 QUIC 在移動端的表現也會比 TCP 好。因爲 TCP 是基於 IP 和端口去識別連接的,這種方式在多變的移動端網絡環境下是很脆弱的。但是 QUIC 是通過 ID 的方式去識別一個連接,不管你網絡環境如何變化,只要 ID 不變,就能迅速重連上。

2. 0RTT

通過使用類似 TCP 快速打開的技術,緩存當前會話的上下文,在下次恢復會話的時候,只需要將之前的緩存傳遞給服務端驗證通過就可以進行傳輸了。

0RTT 建連可以說是 QUIC 相比 HTTP2 最大的性能優勢。那什麼是 0RTT 建連呢?

這裏面有兩層含義:

上圖左邊是 HTTPS 的一次完全握手的建連過程,需要 2-3 個 RTT 纔開始傳輸數據,右邊 QUIC 協議在第一個包就可以包含有效的應用數據

當然,QUIC 協議可以實現 0RTT ,但這也是有條件的,實際上是首次連接 1RTT,非首次連接 0RTT,首次連接過程:

可以看到,首次連接的時候,在第 4 步時,就已經開始發送實際的業務數據了,而第 1 - 3 步正好一去一回花費了 1RTT 時間,所以,首次連接的成本是 1RTT

3. 向前糾錯機制

QUIC 協議有一個非常獨特的特性,稱爲向前糾錯 (Forward Error Correction,FEC),每個數據包除了它本身的內容之外,還包括了部分其他數據包的數據,因此少量的丟包可以通過其他包的冗餘數據直接組裝而無需重傳。

向前糾錯犧牲了每個數據包可以發送數據的上限,但是減少了因爲丟包導致的數據重傳,因爲數據重傳將會消耗更多的時間(包括確認數據包丟失、請求重傳、等待新數據包等步驟的時間消耗)。

假如說這次我要發送三個包,那麼協議會算出這三個包的異或值並單獨發出一個校驗包,也就是總共發出了四個包。

當出現其中的非校驗包丟包的情況時,可以通過另外三個包計算出丟失的數據包的內容。

當然這種技術只能使用在丟失一個包的情況下,如果出現丟失多個包就不能使用糾錯機制了,只能使用重傳的方式了。

4. 加密認證的報文

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

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

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

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

QUIC 和 HTTP/3 前景發展展望

QUIC 協議雖然是基於 UDP 來實現的,但它將 TCP 的重要功能都進行了實現和優化,同時在加密傳輸方向的嘗試也推動了 TLS1.3 的發展,未來還是可期的

只是現在 TCP 協議的勢力過於強大,很多網絡設備甚至對於 UDP 數據包做了很多不友好的策略,所以現在暫時還是 TCP 的天下🤦‍♀️,不過 QUIC 已經展現了強大的生命力,讓我們拭目以待吧!

參考

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