HTTP/3來了!存續(xù)二十多年的TCP協(xié)議最終被拋棄!
6 月 6 日,IETF QUIC 和 HTTP 工作組成員 Robin Marx 宣布,經(jīng)過 5 年的努力,HTTP/3 被標準化為 RFC 9114,這是 HTTP 超文本傳輸協(xié)議的第三個主要版本。同時,HTTP/2 也更新為 RFC 9113標準,HTTP/1.1 和通用 HTTP 語義和緩存概念在 RFC 9110-9112 中也得到了加強。
TCP 是 Internet 上使用和部署最廣泛的協(xié)議之一,多年來一直被視為網(wǎng)絡基石,隨著HTTP/3正式被標準化,QUIC協(xié)議成功“上位”,UDP“取代”TCP成為基礎協(xié)議,TCP究竟“輸”在哪里?
?????
HTTP/3 采用了谷歌多年探索的基于 UDP 的 QUIC 協(xié)議,原名叫 HTTP-over-QUIC,在 2018 年被 IETF 批準更名為 HTTP/3。目前,Cloudflare、Google Chrome、Firefox Nightly 均表示支持 HTTP/3。
為什么我們需要 HTTP/3?
很多人可能都會有這樣一個疑問,為什么在 2015 年才標準化了 HTTP/2 ,這么快就需要 HTTP/3?
事實上,我們并不是真的需要新的 HTTP 版本,而是需要對底層傳輸控制協(xié)議(TCP) 進行升級。
TCP與HTTP的不解之緣
HTTP(超文本傳輸協(xié)議 1.0)的第一個正式版本在 1996 年完成。但是HTTP/1.0 沒有充分考慮分層代理、緩存、長連接的需求和虛擬主機的影響。所以在一年后HTTP/1.1發(fā)布,這也是使用最廣泛的版本。
在 HTTP/1.1 中, 瀏覽器通過 TCP 連接一次只能下載一個文件, 如果一個頁面需要 10 個 js 文件, 那么這些文件將會按順序下載。一個文件的延遲就會阻塞后面的其他內(nèi)容, 也就是我們常說的隊頭阻塞。
2015年, HTTP 協(xié)議迎來了更新, HTTP/2發(fā)布。HTTP/2 的一大特點是多路復用。引入了二進制幀和流機制,允許使用單個 TCP 連接, 通過 Stream 并行下載資源, 提高了傳輸效率。然而HTTP/2的多路復用技術使得多個請求其實是基于同一個TCP連接的,因此在HTTP/2中,TCP隊頭阻塞造成的影響會更大,如果某一個請求造成了TCP隊頭阻塞,那么多個請求都會受到影響。
事實上,在丟包率高的環(huán)境中,HTTP/1.1 性能更好。
此外,發(fā)起 HTTP 請求時,需要經(jīng)過 TCP 三次握手和四次揮手的過程,整個過程共需要 3 個 RTT 的時延才能發(fā)出請求數(shù)據(jù)。如果客戶端和服務器相距遙遠,則每RTT可能會花費超過 100 毫秒,從而導致明顯的延遲。
RTT:往返時間(Round Trip Time),指一個請求從客戶端瀏覽器發(fā)送一個請求數(shù)據(jù)包到服務器,再從服務器得到響應數(shù)據(jù)包的這段時間。RTT 是反映網(wǎng)絡性能的一個重要指標。
?????
幾十年來,TCP 一直是網(wǎng)絡的基石,但種種問題讓大家不得不思考取代它的方法,這就是——QUIC,QUIC在幾個關鍵方面與 TCP 有很大不同,直接在其上運行 HTTP/2 將非常困難。因此,HTTP/3 本身是對 HTTP/2 的一個相對較小的改編,以使其與新的 QUIC 協(xié)議兼容。
?????
什么是QUIC協(xié)議
QUIC是一種通用、安全、多路復用的傳輸層新型網(wǎng)絡協(xié)議,它的目標是取代TCP。
- 2012年,QUIC協(xié)議由當時還在谷歌任職的Jim Roskind開發(fā)。
- 2013年,QUIC正式對外公布。
- 2015年,QUIC被提交給IETF進行標準化。
但是直到六年以后,也就是2021年5月,IETF才發(fā)布了第一版標準化的QUIC,被命名為RFC 9000。同時,IETF還發(fā)布使用了QUIC的HTTP/3標準化版本。QUIC吸納了很多與TCP類似的屬性,還有TLS加密,將它們置于UDP傳輸之上的應用層中。
????
QUIC與 TCP 非常相似,除了 HTTP 和網(wǎng)頁加載之外,還可以將其用于許多用例。例如,DNS、SSH、SMB、RTP 等都可以在 QUIC 上運行。
UDP+QUIC=最佳拍檔
UDP 是最基本的傳輸協(xié)議。除了端口號(例如,HTTP 使用端口 80,HTTPS 使用 443,DNS 使用端口 53)之外,它實際上不提供任何特性。它不通過握手建立連接,也不可靠:如果UDP包丟失,它不會自動重傳。UDP 的“盡力而為”方法不保證可靠性,無需等待握手,也沒有 HoL 阻塞。在實踐中,UDP協(xié)議主要用于實時性要求很高,但不要求完整性的應用,例如實時視頻會議或者游戲等。它對于需要較低的預先延遲的情況也很有用,例如,DNS域名查找只需要一個來回就可以完成。
在 UDP 之上,QUIC 結合了 TCP 數(shù)十年的部署和實踐經(jīng)驗,能夠實現(xiàn)幾乎所有的 TCP的特性。QUIC 的傳輸是絕對可靠的,可以通過流量控制和擁塞控制機制來防止過載,并且以比 TCP 更智能、更高效的方式實現(xiàn)了這些功能。
QUIC 對于TCP 的改進主要可歸結為四個方面:QUIC 與 TLS 深度集成、QUIC 支持多個獨立的字節(jié)流、QUIC 使用連接 ID、QUIC 使用幀(frame)。
QUIC 與 TLS 深度集成
TLS(傳輸層安全協(xié)議)負責保護和加密通過 Internet 發(fā)送的數(shù)據(jù)。當使用 HTTPS 時,純文本 HTTP 數(shù)據(jù)首先由 TLS 加密,然后由 TCP 傳輸。1.2 及更低版本的TLS通常需要兩次RTT,新版本的 TLS 1.3 只需一次RTT。
????
在互聯(lián)網(wǎng)早期,加密流量在處理方面的成本很高,因此很多情況下并不是必要的。TLS 是一個完全獨立的協(xié)議,可以選擇是否在 TCP 之上使用,這也是區(qū)分 HTTP(沒有TLS)和 HTTPS(有TLS)的原因。
隨著時間的推移,我們對互聯(lián)網(wǎng)安全的態(tài)度已經(jīng)轉變?yōu)椤澳J安全”。因此QUIC的設計者選擇將加密深深地嵌入到 QUIC 本身中。雖然 TLS 1.3 仍然可以在 TCP 之上獨立運行,但 QUIC 封裝了 TLS 1.3。換句話說,沒有 TLS 就無法使用 QUIC;QUIC(以及 HTTP/3)始終是完全加密的。此外,QUIC 還加密了幾乎所有的數(shù)據(jù)包頭字段。這為 QUIC 提供了幾個好處:
- QUIC 對用戶來說更安全:QUIC沒有辦法明文運行,因此網(wǎng)絡攻擊者的選擇也更少。
- QUIC 的連接設置更快:雖然對于 TLS-over-TCP,兩種協(xié)議都需要各自單獨的握手,但 QUIC 將傳輸和加密握手合二為一,從而節(jié)省了一次往返時間。
- QUIC 更容易更新:如果在未來想為 QUIC 添加新功能,我們只必須更新終端設備,而不是所有的中間件。
QUIC 支持多個獨立的字節(jié)流
對于 HTTP/1.1,資源加載過程非常簡單,因為每個文件都有自己的 TCP 連接。例如,如果我們有文件 A、B、C,我們將有三個 TCP 連接。第一個將看到 AAAA 的字節(jié)流,第二個 BBBB,第三個 CCCC(每個字母重復都是一個 TCP包)。這可行,但也非常低效,因為每個新的連接都會產(chǎn)生一些開銷。
HTTP/2 的主要目標之一就是改善這種情況。HTTP/2 協(xié)議不再為每個文件打開一個新的 TCP 連接,而是通過單個 TCP 連接下載不同的資源。這是通過多路復用不同的字節(jié)流來實現(xiàn)的。舉例來看,同樣是傳輸A、B、C三個文件,我們將獲得一個 TCP 連接,傳入的數(shù)據(jù)形式可以是 AABBCCAABBCC等。通常情況下,使用HTTP/2 跟HTTP/1.1 一樣快或快一點,但開銷要少得多。
????
HTTP/2的多路復用機制解決了HTTP層的隊頭阻塞問題,但是在TCP層仍然存在隊頭阻塞問題。
TCP協(xié)議在收到數(shù)據(jù)包之后,這部分數(shù)據(jù)可能是亂序到達的,但是TCP必須將所有數(shù)據(jù)收集排序整合后給上層使用,如果其中某個包丟失了,就必須等待重傳,從而出現(xiàn)某個丟包數(shù)據(jù)阻塞整個連接的數(shù)據(jù)使用。例如,HTTP 級別的 AABBCCAABBCC,在TCP 眼里它只是 XXXXXXXXXXXX ,如果此時B丟失,它不會發(fā)現(xiàn)到底是誰丟失,而是整個重傳。
解決傳輸層的隊頭阻塞是 QUIC 的主要目標之一。與 TCP 不同,QUIC 清楚地意識到它正在復用多個獨立的字節(jié)流。因此,QUIC 可以在每個流的基礎上執(zhí)行丟包檢測和恢復邏輯。
在上述場景中,QUIC 只會保留 B 的數(shù)據(jù),并且盡快將 A 和 C 的數(shù)據(jù)傳遞到 HTTP/3 層。
????
QUIC 使用連接 ID
一個 TCP 連接是由四元組(源 IP 地址,源端口,目標 IP 地址,目標端口)確定的,這意味著如果 IP 地址或者端口變動了,就會導致需要 TCP 與 TLS 重新握手,這不利于移動設備切換網(wǎng)絡的場景,比如 4G 網(wǎng)絡環(huán)境切換成 WIFI。這些問題都是 TCP 協(xié)議固有的問題。
????
為了解決這個問題,QUIC 引入了一個名為連接ID(connection identifier,CID)的新概念。每個連接在 4 元組之上分配了另一個編號,該編號在兩個端點之間唯一標識它。
????
更重要的是,因為這個 CID 是在 QUIC 本身的傳輸層定義的,所以在網(wǎng)絡之間移動時它不會改變。通過這種設置,即使 4 元組中的某一項發(fā)生了變化,QUIC 服務器和客戶端只需查看 CID即可知道它是同一個舊連接,可以繼續(xù)使用它。不需要重新握手,下載狀態(tài)可以保持原樣。這個功能通常稱為連接遷移。
QUIC 使用幀(frame)
與 TCP 不同,QUIC 不使用單個固定的數(shù)據(jù)包頭來發(fā)送所有協(xié)議元數(shù)據(jù)。相反,QUIC 具有短的數(shù)據(jù)包頭,并在數(shù)據(jù)包有效載荷內(nèi)使用各種“幀”來傳達額外信息。例如,一個ACK幀(用于確認)、一個NEW_CONNECTION_ID幀(用于幫助建立連接遷移)和一個STREAM幀(用于承載數(shù)據(jù)),如下圖所示:
????
這主要是一種優(yōu)化,因為不是每個包都攜帶所有可能的元數(shù)據(jù)(因此TCP包頭通常會浪費相當多的字節(jié))。使用幀還有一個好處,在未來將新幀類型定義為QUIC的擴展將非常容易。例如,一個非常重要的框架是DATAGRAMframe,它允許通過加密的 QUIC 連接發(fā)送不可靠的數(shù)據(jù)。
總結
總的來說,QUIC相較于TCP有許多優(yōu)點,但是想要真正實現(xiàn)全面推廣也是存在一些困難的。很多企業(yè)、運營商和組織對53端口(DNS)以外的UDP流量會進行攔截或者限流(這些流量常被濫用于攻擊),因此基于UDP的QUIC協(xié)議的傳輸可能會受到屏蔽。此外,很多中間設備對于UDP的支持和優(yōu)化程度也并不高。
不過,盡管還存在一些未知的困難,但HTTP/3.0的時代一定會到來的!