真正“搞”懂HTTP協議14之HTTP3

  我們前一篇學習了HTTP/2,相比於HTTP/1,HTTP/2在性能上有了大幅的改進,但是HTTP/2因爲底層還是基於TCP協議的,雖然HTTP/2在應用層引入了流的概念,利用多路複用解決了隊頭阻塞的問題,但是在TCP中隊頭阻塞的問題仍舊存在。

  又由於TCP協議的僵化、TCP的慢啓動,爲了確保連接建立而產生的延遲問題等頑固問題。HTTP/2雖然在性能上達到了極致,但是還是改變不了底層TCP的性能影響。畢竟應用層。得,死路一條。那怎麼辦呢?

一、QUIC協議

  既然不能用TCP,那就用UDP好啦。我們來看張圖,把我們學過的協議的棧層都羅列一下,方便對比:

   HTTPS的SSL和TLS我們在下一篇就開始聊,先不管。我們看HTTP/1、HTTPS、HTTP/2,和HTTP3在傳輸層有啥區別?HTTP/3用的是UDP。因爲UDP是無序的,包與包之間沒有依賴關係,就像HTTP/2的多路複用一樣,從根本上解決了TCP的隊頭阻塞。

  但是,你肯定知道,UDP是一個簡單的,不可靠的協議,只是對IP協議的一層很薄的包裝,和TCP相比,它的實際應用很少。不過正是因爲它簡單,不需要建連和斷連,通信成本低,也就非常靈活、高效,“可塑性”很強。

  所以,QUIC 就選定了 UDP,在它之上把 TCP 的那一套連接管理、擁塞窗口、流量控制等“搬”了過來,“去其糟粕,取其精華”,打造出了一個全新的可靠傳輸協議,可以認爲是“新時代的 TCP”。

  QUIC 最早是由 Google 發明的,被稱爲 gQUIC。而當前正在由 IETF 標準化的 QUIC 被稱爲 iQUIC。兩者的差異非常大。gQUIC 混合了 UDP、TLS、HTTP,是一個應用層的協議。而 IETF 則對 gQUIC 做了“清理”,把應用部分分離出來,形成了 HTTP/3,原來的 UDP 部分“下放”到了傳輸層,所以 iQUIC 有時候也叫“QUIC-transport”。接下來要說的 QUIC 都是指 iQUIC,要記住,它與早期的 gQUIC 不同,是一個傳輸層的協議,和 TCP 是平級的。

  聊到這裏,我又想起了之前說過的話,如果一層不行,那就再加一層~

特點

  瞭解了QUIC的基本概念,我們再來看看QUIC的特點,這樣的特點給我們帶來了哪些好處。

  前面說過,QUIC是基於UDP的,而UDP是無連接的,根本就不需要握手和揮手,所以天生比TCP快很多。

  就像 TCP 在 IP 的基礎上實現了可靠傳輸一樣,QUIC 也基於 UDP 實現了可靠傳輸,保證數據一定能夠抵達目的地。它還引入了類似 HTTP/2 的“流”和“多路複用”,單個“流”是有序的,可能會因爲丟包而阻塞,但其他“流”不會受到影響。

  並且,QUIC全面使用加密通信,這樣可以很好的抵禦篡改和協議僵化。

  另外,QUIC並不是建立在TLS之上的,而是內部包含了TLS。它使用自己的幀“接管”了 TLS 裏的“記錄”,握手消息、警報消息都不使用 TLS 記錄,直接封裝成 QUIC 的幀發送,省掉了一次開銷。

細節

  QUIC的內容很多,我們只簡單的聊一聊兩個內部的關鍵知識點。

  QUIC基本數據傳輸單位是包(packet)和幀(frame),一個包由多個幀組成,包面向的是”連接“,幀面向的是”流“。

  QUIC 使用不透明的“連接 ID”來標記通信的兩個端點,客戶端和服務器可以自行選擇一組 ID 來標記自己,這樣就解除了 TCP 裏連接對“IP 地址 + 端口”(即常說的四元組)的強綁定,支持“連接遷移”(Connection Migration)。換句話說,當IP變化的時候,QUIC連接裏的兩端ID不會變,邏輯上連接沒有中斷,所以無需像TCP一樣再重新連接,節省了一定的性能,消除了連接成本,實現連接的無縫遷移。

二、HTTP/3

  瞭解了QUIC後,再來學習HTTP/3就要容易很多了。

  因爲 QUIC 本身就已經支持了加密、流和多路複用,所以 HTTP/3 的工作減輕了很多,把流控制都交給 QUIC 去做。調用的不再是 TLS 的安全接口,也不是 Socket API,而是專門的 QUIC 函數。不過這個“QUIC 函數”還沒有形成標準,必須要綁定到某一個具體的實現庫。

  HTTP/3 裏仍然使用流來發送“請求 - 響應”,但它自身不需要像 HTTP/2 那樣再去定義流,而是直接使用 QUIC 的流,相當於做了一個“概念映射”。

  HTTP/3中的頭部壓縮算法也升級成了“QPACK”,使用方式上也做了改變。雖然也分成靜態表和動態表,但在流上發送 HEADERS 幀時不能更新字段,只能引用,索引表的更新需要在專門的單向流上發送指令來管理,解決了 HPACK 的“隊頭阻塞”問題。另外,QPACK 的字典也做了優化,靜態表由之前的 61 個增加到了 98 個,而且序號從 0 開始,也就是說“:authority”的編號是 0。

  還有一個有趣的點是,HTTP/3 沒有指定默認的端口號,也就是說不一定非要在 UDP 的 80 或者 443 上提供 HTTP/3 服務。那麼,該怎麼“發現”HTTP/3 呢?

  這就要用到 HTTP/2 裏的“擴展幀”了。瀏覽器需要先用 HTTP/2 協議連接服務器,然後服務器可以在啓動 HTTP/2 連接後發送一個“Alt-Svc”幀,包含一個“h3=host:port”的字符串,告訴瀏覽器在另一個端點上提供等價的 HTTP/3 服務。瀏覽器收到“Alt-Svc”幀,會使用 QUIC 異步連接指定的端口,如果連接成功,就會斷開 HTTP/2 連接,改用新的 HTTP/3 收發數據。

三、示例

  如果你想嘗試HTTP/3的例子,我們可以在這個網址玩一下,https://quic.nginx.org/。如果不行的話,就需要多刷新幾下,如果還是不行,那就需要打開Chrome瀏覽器在地址欄輸入“chrome://flags”,打開設置頁面,然後搜索“QUIC”,找到啓用 QUIC 的選項,把它改爲“Enabled”。就像這樣:

  然後,再去刷新幾下,運氣好的話,就可以看到這樣的Network了:

    如果你發現不管你怎麼刷新都不行的話,試試把你的VPN關了應該會好的~

  這是整個H3的報文:

   是不是有那麼一點點陌生又熟悉?

四、小結

  本篇,我們簡單的聊了聊HTTP/3,聊了聊QUIC是什麼,它是怎麼解決之前HTTP爲之苦惱的隊頭阻塞的問題。以及HTTP/3的協議棧相比於HTTP/2、HTTP/1有什麼區別,多了哪些內容等等。HTTP/3可以說是集大成之作,把之前所有版本的HTTP協議的精華摘取,去其糟粕,形成了現在幾乎完美的HTTP/3協議。

  那麼關於“性能”部分,我們就到此爲止了,後面我們會花幾篇文章的時間,來學一學HTTPS,也就是HTTP是如何在“安全”這條路上走向完善的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章