說一下 HTTP-3 新特性,爲什麼選擇使用 UDP 協議?
引言
本文主要分爲以下幾個方面循序漸進走進 HTTP/3:
-
HTTP/2 和 TCP 的致命缺陷
-
QUIC 協議爲什麼選擇 UDP
-
QUIC 和 HTTP/3 新特性
-
QUIC 和 HTTP/3 前景發展展望
HTTP/2 和 TCP 的缺陷
HTTP/2 使用二進制傳輸、Header 壓縮(HPACK)、多路複用等,相較於 HTTP/1.1 大幅提高了數據傳輸效率,但它仍然存在着以下幾個致命問題(主要由底層支撐的 TCP 協議造成):
-
建立連接時間長
-
隊頭阻塞問題相較於 HTTP/1.1 更嚴重
1. 建立連接時間長
RTT 往返時間
如何定義建立連接時間喃?這裏引入一個概念:RTT(Round-Trip Time),往返時間,表示從發送端發送數據開始,到發送端收到來自接收端的確認(接收端收到數據後便立即發送確認,不包含數據傳輸時間)總共經歷的時間,即通信一來一回的時間
TCP 建立連接時間
TCP 通過三次揮手建立了 TCP 虛擬通道,它總共需要花費:
-
一去 (SYN):客戶端向服務端發送連接請求報文段。該報文段中包含自身的數據通訊初始序號。請求發送後,客戶端便進入 SYN-SENT 狀態
-
二回 (SYN+ACK):服務端收到連接請求報文段後,如果同意連接,則會發送一個應答,該應答中也會包含自身的數據通訊初始序號,發送完成後便進入 SYN-RECEIVED 狀態
-
三去 (ACK):當客戶端收到連接同意的應答後,還要向服務端發送一個確認報文。客戶端發完這個報文段後便進入 ESTABLISHED 狀態,服務端收到這個應答後也進入 ESTABLISHED 狀態,此時連接建立成功
相當於一個半來回,故 TCP 建立連接時間 = 1.5 RTT
HTTP 交易時間
客戶端在請求數據的時候,首先花費 1.5 RTT 建立 TCP 連接,然後 TCP 纔開始傳輸 HTTP 請求,瀏覽器收到服務器的響應,又要等待的時間爲:
-
一去(HTTP Request)
-
二回 (HTTP Responses)
故 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:
-
**一去:**客戶端發送一個隨機數 C,客戶端的 TLS 版本號以及支持的密碼套件列表給服務器端
-
**二回:**服務端收到客戶端的隨機值,自己也產生一個隨機值 S ,並根據客戶端需求的協議和加密方式來使用對應的方式,並且發送自己的證書(如果需要驗證客戶端證書需要說明)
-
**三去:**客戶端收到服務端的證書並驗證是否有效,驗證通過會再生成一個隨機值 pre-master,通過服務端證書的公鑰去加密這個隨機值併發送給服務端。如果服務端需要驗證客戶端證書的話會附帶證書(雙向認證,比如網上銀行用 U 盾)
-
四回: 服務端收到加密過的隨機值並使用私鑰解密獲得第三個隨機值,這時候兩端都擁有了三個隨機值,可以通過這三個隨機值(C/S 加 pre-master 算出主密鑰)按照之前約定的加密方式生成密鑰,接下來的通信就可以通過該會話密鑰來加密解密
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 開發的設備和協議非常多,兼容困難
-
TCP 協議棧是 Linux 內部的重要部分,修改和升級成本很大
-
UDP 本身是無連接的、沒有建鏈和拆鏈成本
-
UDP 的數據包無隊頭阻塞問題
-
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 建連呢?
這裏面有兩層含義:
-
傳輸層 0RTT 就能建立連接。
-
加密層 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 已經展現了強大的生命力,讓我們拭目以待吧!
參考
-
圖解 | 爲什麼 HTTP3.0 使用 UDP 協議:https://network.51cto.com/art/202009/625999.htm
-
如何看待 HTTP/3 ?:https://www.zhihu.com/question/302412059/answer/533223530
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/WbNwnlW0C9SAYbn4Yedqnw