說一下 HTTP/3 新特性,為什么選擇使用 UDP 協(xié)議?
點擊上方 三分鐘學(xué)前端,關(guān)注公眾號
回復(fù)交流,加入前端編程面試算法每日一題群
引言
本文主要分為以下幾個方面循序漸進走進 HTTP/3:
-
HTTP/2 和 TCP 的致命缺陷 -
QUIC 協(xié)議為什么選擇 UDP -
QUIC 和 HTTP/3 新特性 -
QUIC 和 HTTP/3 前景發(fā)展展望
HTTP/2 和 TCP 的缺陷
HTTP/2 使用二進制傳輸、Header 壓縮(HPACK)、多路復(fù)用等,相較于 HTTP/1.1 大幅提高了數(shù)據(jù)傳輸效率,但它仍然存在著以下幾個致命問題(主要由底層支撐的 TCP 協(xié)議造成):
-
建立連接時間長 -
隊頭阻塞問題相較于 HTTP/1.1 更嚴(yán)重
1. 建立連接時間長
RTT 往返時間
如何定義建立連接時間喃?這里引入一個概念:RTT(Round-Trip Time),往返時間,表示從發(fā)送端發(fā)送數(shù)據(jù)開始,到發(fā)送端收到來自接收端的確認(接收端收到數(shù)據(jù)后便立即發(fā)送確認,不包含數(shù)據(jù)傳輸時間)總共經(jīng)歷的時間,即通信一來一回的時間
TCP 建立連接時間
TCP 通過三次揮手建立了 TCP 虛擬通道,它總共需要花費:
-
一去 (SYN):客戶端向服務(wù)端發(fā)送連接請求報文段。該報文段中包含自身的數(shù)據(jù)通訊初始序號。請求發(fā)送后,客戶端便進入 SYN-SENT 狀態(tài) -
二回 (SYN+ACK):服務(wù)端收到連接請求報文段后,如果同意連接,則會發(fā)送一個應(yīng)答,該應(yīng)答中也會包含自身的數(shù)據(jù)通訊初始序號,發(fā)送完成后便進入 SYN-RECEIVED 狀態(tài) -
三去 (ACK):當(dāng)客戶端收到連接同意的應(yīng)答后,還要向服務(wù)端發(fā)送一個確認報文。客戶端發(fā)完這個報文段后便進入 ESTABLISHED 狀態(tài),服務(wù)端收到這個應(yīng)答后也進入 ESTABLISHED 狀態(tài),此時連接建立成功
相當(dāng)于一個半來回,故 TCP 建立連接時間 = 1.5 RTT
HTTP 交易時間
客戶端在請求數(shù)據(jù)的時候,首先花費 1.5 RTT 建立 TCP 連接,然后 TCP 才開始傳輸 HTTP 請求,瀏覽器收到服務(wù)器的響應(yīng),又要等待的時間為:
-
一去(HTTP Request) -
二回 (HTTP Responses)
故 HTTP 交易時間 = 1 RTT
由于 TCP 在第三次握手的時候,不需要等待服務(wù)器端的響應(yīng),所以節(jié)省 0.5 RTT,那么基于 TCP 傳輸?shù)?HTTP 通信,一共花費的時間總和:
HTTP 通信時間總和 = TCP 建立連接時間 + HTTP 交易時間 = 1 RTT + 1 RTT = 2 RTT
HTTPS 通信時間
HTTP/2 延續(xù)了 HTTP/1 的“明文”特點,可以像以前一樣使用明文傳輸數(shù)據(jù),不強制使用加密通信,但 HTTPS 已經(jīng)是大勢所趨,各大主流瀏覽器都公開宣布只支持加密的 HTTP/2,所以,真實應(yīng)用中的 HTTP/2 是還是加密的:
HTTPS 其實是 HTTP+SSL/TLS 的簡稱
所以,HTTPS 通信時間 = TCP建立連接時間 + TLS 連接時間 + HTTP交易時間
TLS 連接時間
在 TLS 1.2 協(xié)議的握手,需要 2 個 RTT:
-
一去:客戶端發(fā)送一個隨機數(shù) C,客戶端的 TLS 版本號以及支持的密碼套件列表給服務(wù)器端 -
二回:服務(wù)端收到客戶端的隨機值,自己也產(chǎn)生一個隨機值 S ,并根據(jù)客戶端需求的協(xié)議和加密方式來使用對應(yīng)的方式,并且發(fā)送自己的證書(如果需要驗證客戶端證書需要說明) -
三去:客戶端收到服務(wù)端的證書并驗證是否有效,驗證通過會再生成一個隨機值 pre-master,通過服務(wù)端證書的公鑰去加密這個隨機值并發(fā)送給服務(wù)端。如果服務(wù)端需要驗證客戶端證書的話會附帶證書(雙向認證,比如網(wǎng)上銀行用 U 盾) -
四回: 服務(wù)端收到加密過的隨機值并使用私鑰解密獲得第三個隨機值,這時候兩端都擁有了三個隨機值,可以通過這三個隨機值(C/S 加 pre-master 算出主密鑰)按照之前約定的加密方式生成密鑰,接下來的通信就可以通過該會話密鑰來加密解密
HTTPS 通信時間總和 = TCP 建立連接時間 + TLS 連接時間 + HTTP交易時間 = 1 RTT + 2 RTT + 1 RTT = 4 RTT
如果服務(wù)器距離客戶端很近,RTT 時間較短 < 10ms,那么 HTTPS 通信時間也不會超過 40 ms,用戶不會感知,但如果距離較遠,相隔上萬公里,一個 RTT 時間通常在200ms以上,那么 HTTPS 通信將花費 800ms 甚至 1s 以上,這就嚴(yán)重影響到用戶體驗了
注意:在 TLS 1.3 協(xié)議中,首次建立連接只需要一個 RTT,后面恢復(fù)連接不需要 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 更嚴(yán)重
因為 HTTP/2 使用了多路復(fù)用,一般來說同一域名下只需要使用一個 TCP 連接。當(dāng)這個連接中出現(xiàn)了丟包的情況,那就會導(dǎo)致 HTTP/2 的表現(xiàn)情況反倒不如 HTTP/1 了。
因為在出現(xiàn)丟包的情況下,整個 TCP 都要開始等待重傳,也就導(dǎo)致了后面的所有數(shù)據(jù)都被阻塞了。但是對于 HTTP/1 來說,可以開啟多個 TCP 連接,出現(xiàn)這種情況反到只會影響其中一個連接,剩余的 TCP 連接還可以正常傳輸數(shù)據(jù)。
QUIC 協(xié)議為什么選擇 UDP
那么可能就會有人考慮到去修改 TCP 協(xié)議,其實這已經(jīng)是一件不可能完成的任務(wù)了。因為 TCP 存在的時間實在太長,已經(jīng)充斥在各種設(shè)備中,并且這個協(xié)議是由操作系統(tǒng)實現(xiàn)的,更新起來不大現(xiàn)實。
基于這個原因,Google 就更起爐灶搞了一個基于 UDP 協(xié)議的 QUIC 協(xié)議
谷歌這樣做看似出乎意料的,但我們對比一下 TCP 與 UDP 就會發(fā)現(xiàn),這是很有道理的:
-
基于 TCP 開發(fā)的設(shè)備和協(xié)議非常多,兼容困難 -
TCP 協(xié)議棧是 Linux 內(nèi)部的重要部分,修改和升級成本很大 -
UDP 本身是無連接的、沒有建鏈和拆鏈成本 -
UDP 的數(shù)據(jù)包無隊頭阻塞問題 -
UDP 改造成本小
從上面的對比可以知道,谷歌要想從 TCP 上進行改造升級絕非易事,但是 UDP 雖然沒有 TCP 為了保證可靠連接而引發(fā)的問題,但是 UDP 本身不可靠,又不能直接用。
所以,谷歌決定在 UDP 基礎(chǔ)上改造一個具備 TCP 協(xié)議優(yōu)點的新協(xié)議也就順理成章了,這個新協(xié)議就是 QUIC 協(xié)議(Quick UDP Internet Connection),并且使用在了 HTTP/3 上,當(dāng)然 HTTP/3 之前名為 HTTP-over-QUIC,從這個名字中我們也可以發(fā)現(xiàn),HTTP/3 最大的改造就是使用了 QUIC
QUIC 和 HTTP/3 新特性
QUIC 雖然基于 UDP,但是在原本的基礎(chǔ)上新增了很多功能,比如多路復(fù)用、0-RTT、使用 TLS1.3 加密、流量控制、有序交付、重傳等等功能。這里我們就挑選幾個重要的功能學(xué)習(xí)下這個協(xié)議的內(nèi)容。
1. 多路復(fù)用,解決隊頭阻塞問題
雖然 HTTP/2 支持了多路復(fù)用,但是 TCP 協(xié)議終究是沒有這個功能的。QUIC 原生就實現(xiàn)了這個功能
QUIC 協(xié)議是基于 UDP 協(xié)議實現(xiàn)的,同一個 QUIC 連接上可以創(chuàng)建多個 stream(數(shù)據(jù)流) 來發(fā)送多個 HTTP 請求,并且,多個 stream 之間沒有依賴,傳輸?shù)膯蝹€ stream可以保證有序交付且不會影響其他的數(shù)據(jù)流
例如下圖,stream2 丟了一個 UDP 包,不會影響后面跟著 Stream3 和 Stream4。這樣的技術(shù)就解決了之前 TCP 存在的隊頭阻塞問題。
并且 QUIC 在移動端的表現(xiàn)也會比 TCP 好。因為 TCP 是基于 IP 和端口去識別連接的,這種方式在多變的移動端網(wǎng)絡(luò)環(huán)境下是很脆弱的。但是 QUIC 是通過 ID 的方式去識別一個連接,不管你網(wǎng)絡(luò)環(huán)境如何變化,只要 ID 不變,就能迅速重連上。
2. 0RTT
通過使用類似 TCP 快速打開的技術(shù),緩存當(dāng)前會話的上下文,在下次恢復(fù)會話的時候,只需要將之前的緩存?zhèn)鬟f給服務(wù)端驗證通過就可以進行傳輸了。
0RTT 建連可以說是 QUIC 相比 HTTP2 最大的性能優(yōu)勢。那什么是 0RTT 建連呢?
這里面有兩層含義:
-
傳輸層 0RTT 就能建立連接。 -
加密層 0RTT 就能建立加密連接。
上圖左邊是 HTTPS 的一次完全握手的建連過程,需要 2-3 個 RTT才開始傳輸數(shù)據(jù),右邊 QUIC 協(xié)議在第一個包就可以包含有效的應(yīng)用數(shù)據(jù)
當(dāng)然,QUIC 協(xié)議可以實現(xiàn) 0RTT ,但這也是有條件的,實際上是首次連接 1RTT,非首次連接 0RTT,首次連接過程:
可以看到,首次連接的時候,在第 4 步時,就已經(jīng)開始發(fā)送實際的業(yè)務(wù)數(shù)據(jù)了,而第 1 - 3 步正好一去一回花費了 1RTT 時間,所以,首次連接的成本是 1RTT
3. 向前糾錯機制
QUIC 協(xié)議有一個非常獨特的特性,稱為向前糾錯 (Forward Error Correction,F(xiàn)EC),每個數(shù)據(jù)包除了它本身的內(nèi)容之外,還包括了部分其他數(shù)據(jù)包的數(shù)據(jù),因此少量的丟包可以通過其他包的冗余數(shù)據(jù)直接組裝而無需重傳。
向前糾錯犧牲了每個數(shù)據(jù)包可以發(fā)送數(shù)據(jù)的上限,但是減少了因為丟包導(dǎo)致的數(shù)據(jù)重傳,因為數(shù)據(jù)重傳將會消耗更多的時間(包括確認數(shù)據(jù)包丟失、請求重傳、等待新數(shù)據(jù)包等步驟的時間消耗)。
假如說這次我要發(fā)送三個包,那么協(xié)議會算出這三個包的異或值并單獨發(fā)出一個校驗包,也就是總共發(fā)出了四個包。
當(dāng)出現(xiàn)其中的非校驗包丟包的情況時,可以通過另外三個包計算出丟失的數(shù)據(jù)包的內(nèi)容。
當(dāng)然這種技術(shù)只能使用在丟失一個包的情況下,如果出現(xiàn)丟失多個包就不能使用糾錯機制了,只能使用重傳的方式了。
4. 加密認證的報文
TCP 協(xié)議頭部沒有經(jīng)過任何加密和認證,所以在傳輸過程中很容易被中間網(wǎng)絡(luò)設(shè)備篡改,注入和竊聽。比如修改序列號、滑動窗口。這些行為有可能是出于性能優(yōu)化,也有可能是主動攻擊。
但是 QUIC 的 packet 可以說是武裝到了牙齒。除了個別報文比如 PUBLIC_RESET 和 CHLO,所有報文頭部都是經(jīng)過認證的,報文 Body 都是經(jīng)過加密的。
這樣只要對 QUIC 報文任何修改,接收端都能夠及時發(fā)現(xiàn),有效地降低了安全風(fēng)險。
如上圖所示,紅色部分是 Stream Frame 的報文頭部,有認證。綠色部分是報文內(nèi)容,全部經(jīng)過加密。
QUIC 和 HTTP/3 前景發(fā)展展望
QUIC 協(xié)議雖然是基于 UDP 來實現(xiàn)的,但它將 TCP 的重要功能都進行了實現(xiàn)和優(yōu)化,同時在加密傳輸方向的嘗試也推動了TLS1.3的發(fā)展,未來還是可期的
只是現(xiàn)在 TCP 協(xié)議的勢力過于強大,很多網(wǎng)絡(luò)設(shè)備甚至對于UDP數(shù)據(jù)包做了很多不友好的策略,所以現(xiàn)在暫時還是 TCP 的天下???♀?,不過 QUIC 已經(jīng)展現(xiàn)了強大的生命力,讓我們拭目以待吧!
參考
-
圖解|為什么HTTP3.0使用UDP協(xié)議:https://network.51cto.com/art/202009/625999.htm -
如何看待 HTTP/3 ?:https://www.zhihu.com/question/302412059/answer/533223530
來自:https://github.com/Advanced-Frontend/Daily-Interview-Question
