HTTP 3.0 是 HTTP 協議的第三個主要版本,前兩個分別是 HTTP 1.0 和 HTTP 2.0 ,但其實 HTTP 1.1 我認爲纔是真正的 HTTP 1.0。
如果你對 HTTP 1.1 和 HTTP 2.0 不太瞭解的話,可以閱讀筆者的這兩篇文章。
我們大家知道,HTTP 是應用層協議,應用層產生的數據會通過傳輸層協議作爲載體來傳輸到互聯網上的其他主機中,而其中的載體就是 TCP 協議,這是 HTTP 2 之前的主流模式。
但是隨着 TCP 協議的缺點不斷暴露出來,新一代的 HTTP 協議 - HTTP 3.0 毅然決然的切斷了和 TCP 的聯繫,轉而擁抱了 UDP 協議,這麼說不太準確,其實 HTTP 3.0 其實是擁抱了 QUIC 協議,而 QUIC 協議是建立在 UDP 協議基礎上的。
HTTP 3.0
HTTP 3.0 於 2022 年 6 月 6 日正式發佈,IETF 把 HTTP 3.0 標準制定在了 RFC 9114 中,HTTP 3.0 其實相較於 HTTP 2.0 要比 HTTP 2.0 相較於 HTTP 1.1 的變化來說小很多,最大的提升就在於效率,替換 TCP 協議爲 UDP 協議,HTTP 3.0 具有更低的延遲,它的效率甚至要比 HTTP 1.1 快 3 倍以上。
其實每一代 HTTP 協議的不斷髮展都是建立在上一代 HTTP 的缺點上的,就比如 HTTP 1.0 最大的問題就是傳輸安全性和不支持持久連接上,針對此出現了 HTTP 1.1 ,引入了 Keep-Alive 機制來保持長鏈接和 TLS 來保證通信安全性。但此時的 HTTP 協議併發性還做的不夠好。
隨着網絡的不斷髮展,每個網站所需資源(CSS、JavaScript、圖像等)的數量逐年增加,瀏覽器發現自己在獲取和呈現網頁時需要越來越多的併發性。但是由於 HTTP 1.1 只能夠允許客戶端/服務器進行一次 HTTP 請求交換,因此在網絡層獲得併發性的唯一方法是並行使用多個 TCP 連接到同一個源,不過使用多個 TCP 鏈接就失去了 keep-Alive 的意義。
然後出現了 SPDY 協議,主要解決 HTTP 1.1 效率不高的問題,包括降低延遲,壓縮 header 等等,這些已經被 Chrome 瀏覽器證明能夠產生優化效果,後來 HTTP 2.0 基於 SPDY ,並且引入了 流( Stream )的概念,它允許將不同的 HTTP 交換多路複用到同一個 TCP 連接上,從而達到讓瀏覽器重用 TCP 鏈接的目的。
TCP 的主要作用是以正確的順序將整個字節流從一個端點傳輸到另一個端點,但是當流中的某些數據包丟失時,TCP 需要重新發送這些丟失的數據包,等到丟失的數據包到達對應端點時才能夠被 HTTP 處理,這被稱爲 TCP 的隊頭阻塞問題。
那麼可能就會有人考慮到去修改 TCP 協議,其實這已經是一件不可能完成的任務了。因爲 TCP 存在的時間實在太長,已經充斥在各種設備中,並且這個協議是由操作系統實現的,更新起來不大現實。
基於這個原因,Google 就更起爐竈搞了一個基於 UDP 協議的 QUIC 協議,並且使用在了 HTTP/3 上,HTTP/3 之前名爲 HTTP-over-QUIC,從這個名字中我們也可以發現,HTTP/3 最大的改造就是使用了 QUIC。
QUIC 協議
QUIC 的小寫是 quic,諧音 quick,意思就是快
。它是 Google 提出來的一個基於 UDP 的傳輸協議,所以 QUIC 又被叫做快速 UDP 互聯網連接。
首先 QUIC 的第一個特徵就是快,爲什麼說它快,它到底快在哪呢?
我們大家知道,HTTP 協議在傳輸層是使用了 TCP 進行報文傳輸,而且 HTTPS 、HTTP/2.0 還採用了 TLS 協議進行加密,這樣就會導致三次握手的連接延遲:即 TCP 三次握手(一次)和 TLS 握手(兩次),如下圖所示。
對於很多短連接場景,這種握手延遲影響較大,而且無法消除。畢竟 RTT 是人類和效率的終極鬥爭。
相比之下,QUIC 的握手連接更快,因爲它使用了 UDP 作爲傳輸層協議,這樣能夠減少三次握手的時間延遲。而且 QUIC 的加密協議採用了 TLS 協議的最新版本 TLS 1.3,相對之前的 TLS 1.1-1.2,TLS1.3 允許客戶端無需等待 TLS 握手完成就開始發送應用程序數據的操作,可以支持1 RTT 和 0 RTT,從而達到快速建立連接的效果。
我們上面還說過,HTTP/2.0 雖然解決了隊頭阻塞問題,但是其建立的連接還是基於 TCP,無法解決請求阻塞問題。
而 UDP 本身沒有建立連接這個概念,並且 QUIC 使用的 stream 之間是相互隔離的,不會阻塞其他 stream 數據的處理,所以使用 UDP 並不會造成隊頭阻塞。
在 TCP 中,TCP 爲了保證數據的可靠性,使用了序號+確認號機制來實現,一旦帶有 synchronize sequence number 的包發送到服務器,服務器都會在一定時間內進行響應,如果過了這段時間沒有響應,客戶端就會重傳這個包,直到服務器收到數據包並作出響應爲止。
那麼 TCP 是如何判斷它的重傳超時時間呢?
TCP 一般採用的是自適應重傳算法,這個超時時間會根據往返時間 RTT 動態調整的。每次客戶端都會使用相同的 syn 來判斷超時時間,導致這個 RTT 的結果計算的不太準確。
雖然 QUIC 沒有使用 TCP 協議,但是它也保證了可靠性,QUIC 實現可靠性的機制是使用了 Packet Number,這個序列號可以認爲是 synchronize sequence number 的替代者,這個序列號也是遞增的。與 syn 所不同的是,不管服務器有沒有接收到數據包,這個 Packet Number 都會 + 1,而 syn 是隻有服務器發送 ack 響應之後,syn 纔會 + 1。
比如有一個 PN = 10 的數據包在發送的過程中由於某些原因遲遲沒到服務器,那麼客戶端會重傳一個 PN = 11 的數據包,經過一段時間後客戶端收到 PN = 10 的響應後再回送響應報文,此時的 RTT 就是 PN = 10 這個數據包在網絡中的生存時間,這樣計算相對比較準確。
雖然 QUIC 保證了數據包的可靠性,但是數據的可靠性是如何保證的呢?
QUIC 引入了一個 stream offset 的概念,一個 stream 可以傳輸多個 stream offset,每個 stream offset 其實就是一個 PN 標識的數據,即使某個 PN 標識的數據丟失,PN + 1 後,它重傳的仍舊是 PN 所標識的數據,等到所有 PN 標識的數據發送到服務器,就會進行重組,以此來保證數據可靠性。到達服務器的 stream offset 會按照順序進行組裝,這同時也保證了數據的順序性。
衆所周知,TCP 協議的具體實現是由操作系統內核來完成的,應用程序只能使用,不能對內核進行修改,隨着移動端和越來越多的設備接入互聯網,性能逐漸成爲一個非常重要的衡量指標。雖然移動網絡發展的非常快,但是用戶端的更新卻非常緩慢,我仍然看見有很多地區很多計算機還仍舊使用 xp 系統,儘管它早已發展了很多年。服務端系統不依賴用戶升級,但是由於操作系統升級涉及到底層軟件和運行庫的更新,所以也比較保守和緩慢。
QUIC 協議的一個重要特點就是可插拔性,能夠動態更新和升級,QUIC 在應用層實現了擁塞控制算法,不需要操作系統和內核的支持,遇到擁塞控制算法切換時,只需要在服務器重新加載一邊即可,不需要停機和重啓。
我們知道 TCP 的流量控制是通過滑動窗口來實現的,如果你對滑動窗口不太熟悉,你可以看下我寫的這篇文章
在文章後面有提到了滑動窗口的一些概念。
而 QUIC 也實現了流量控制,QUIC 的流量控制也是使用了窗口更新 window_update,來告訴對端它可以接受的字節數。
TCP 協議頭部沒有經過加密和認證,所以在傳輸的過程中很可能被篡改,與之不同的是,QUIC 中的報文頭部都是經過認證,報文也經過加密處理。這樣只要對 QUIC 的報文有任何修改,接收端都能夠及時發現,保證了安全性。
總的來說,QUIC 具有下面這些優勢
- 使用 UDP 協議,不需要三次連接進行握手,而且也會縮短 TLS 建立連接的時間。
- 解決了隊頭阻塞問題。
- 實現動態可插拔,在應用層實現了擁塞控制算法,可以隨時切換。
- 報文頭和報文體分別進行認證和加密處理,保障安全性。
- 連接能夠平滑遷移。
連接平滑遷移指的是,你的手機或者移動設備在 4G 信號下和 WiFi 等網絡情況下切換,不會斷線重連,用戶甚至無任何感知,能夠直接實現平滑的信號切換。
QUCI 協議已經被寫在了 RFC 9000 中。
原文鏈接:HTTP/3 ,它來了。
公衆號有很多精品文章,推薦大家關注下。