淺談 HTTP/3 與 QUIC

Chang Che-Pin
Aug 30 · 16 min read

前言

在 2019 八月中旬時,小弟很榮幸地,有機會在 COSCUP2019 的 SDN x Cloud Native x Golang 議軌中擔任講者。當時的題目為 HTTP/3 Leaks,主要介紹下個世代的 HTTP 協定 — HTTP/3與其所使用的傳輸層協定(Transport Protocol) — QUIC。而似乎是場地限制的關係,本場演講並沒有影片釋出。因此,希望可以藉由這篇文章,簡單地介紹 HTTP/3 與 QUIC,讓更多人了解新協定的特徵功能與運作流程。

值得注意的是,在技術分享與撰寫本文的當下, HTTP/3 與 QUIC 還未確立最終的版本。因此本文的所描述的標準協定是基於時空背景下最新的草稿 — draft-ietf-quic-http-22draft-ietf-quic-transport-22,其內容可能與最終版本有所出入。


簡介

本文章的目的是介紹 HTTP/3 與其底層的 QUIC,其涵蓋的議題包括:

  • 為什麼需要新的 HTTP 協定?
  • 為什麼需要新的傳輸協定 (transport protocol)?
  • QUIC 的特徵
  • HTTP/3 與 HTTP/2 的比較
  • HTTP/3 常見的批評與顧慮

HTTP/2 的缺點

當我們談論到為什麼需要新的 HTTP 協定時,必須先了解目前的 HTTP 版本 (HTTP/2) 遇到了哪些問題。而大致上可以概括成兩點:

  • 傳輸層的 Head-of-Line Blocking
  • HTTP 連線建立過程冗長

傳輸層的 Head-of-Line Blocking

Head-of-line blocking (HOL blocking) 是一種效能受限的現象,指得是當前處理的請求受阻而導致整個序列中的請求都受阻的情況。就像排隊結帳一樣,如果當前結帳的人遲遲無法完成,整個排隊的人龍都會收到影響。

由於 HTTP/2 引進了 multiple streams over a single connection (multiplexing) ,因此成功解決了 HTTP 長久以來應用層的 HOL blocking 問題 (來自同一用戶端的 HTTP 請求,必須照接受的順序回應)。但可惜的是,由於 HTTP/2 採用單一 TCP 連線來做資料傳輸,反倒衍生出了傳輸層的 HOL blocking。

傳輸層的 HOL blocking 指的是,在同一個連線當中,即使封包在應用層中是屬於不同的 stream,TCP 依然會要求它們必須依序傳輸。原因在於TCP 是傳輸層協定,並不暸解上方應用層的邏輯,所以對它來說這些封包都屬於同一個連線。因此在網路環境不穩的情境下,不同 Stream 的封包有可能會在傳輸層中因為其他 stream 封包的遺失與重傳而受堵。

HTTP 連線建立過程冗長

HTTP 在建立連線時,必須先完成 TCP 的 3-way handshake,接著如果要採用 secure 連線,還要額外進行 TLS handshake,而這全部加起來需要 3 個 RTT (round trip time)才能完成。這對 HTTP 請求與回應的延遲時間,要求越來越高的現代網路應用而言,是個頭痛的問題。

成也 TCP,敗也 TCP

從上述 HTTP/2 的兩個主要痛點中可以發現,目前主要問題來自 HTTP 所採用傳輸層協定 TCP。TCP 提供了穩定且可靠的封包傳輸機制,也提供了重傳 (re-transmission) 與錯誤處理 (error handling) 等功能,讓基於 TCP 的應用層協定不用擔心資料遺失等問題, HTTP 也是受惠者。但當網路技術越來越發達,基礎網路建設也越來越強健的同時,TCP 繁瑣的溝通機制與缺乏彈性的設計,反倒成為了 HTTP 發展的阻礙。

有鑑於此,為了解決使用 TCP 所造成的問題,在新一代的 HTTP 中,將不再基於 TCP 訂製其傳輸層協定的規格,而是將其描述成兼具效能與可靠性的全新協定。


一個新的傳輸協定的誕生

承上, 由於 TCP 不再適用新一代的 HTTP ,因此勢必得找到其他替代方案,而基本上有兩種選擇 — 既有的傳輸協定或設計新的。在取捨上,除了符合需求外,最重要的議題在於該協定是否可以成功落地

網路協定的僵化 (Protocol Ossification)

網際網路本身是由非常龐大的網路節點所構成,資料的傳輸必須仰賴兩端點間眾多中間節點的協助才能完成。但網際網路的實體其實並沒有大家所想的那麼進步與高科技,相反地,有大量的中間節點非常陳舊與過時。它們可能有數年至數十年未更新使用的軟體,也認不出許多近年才提出的網路協定與延伸功能。由於這些節點老舊且數量龐大,也造成了新的網路協定非常難以推廣與應用

基於 UDP 的新傳輸協定

為了可以順利普及,一個全新的傳輸協定想必是不可行的。因此,大家開始把歪腦筋動到了另外一個普及的傳輸協定 — UDP 身上:

  • 2012 時,Google 開始設計基於 UDP 的實驗性傳輸協定 — Quick UDP Internet Connections
  • 2015 時,Google 正式向 IETF 提出協定草案 (簡稱 gQUIC),內容包含 Google 如何實作與整合 gQUIC 與 HTTP/2 。接著 IETF 於同年成立 QUIC workgroup。
  • 2016 時, QUIC workgroup 正式提出協定草案(簡稱 ITEF-QUIC 或 QUIC),並著手擬訂細節。

ITEF-QUIC 與 gQUIC 的概念一致,但實作並不相同:

  • gQUIC 基於 Google 的需求,採用客製化的加密方式,且只服務 HTTP。
  • ITEF-QUIC 則被設計成可適用不同應用層協定,並採用標準的 TLS 1.3 (RFC-8446)加密。為此,IETF 將整個 QUIC 中關於傳輸層與應用層的規格切成兩個協定草案,即 QUIC 與 HTTP-over-QUIC (後者於 2018 時被正名為 HTTP/3)。
Overview of HTTP/3 and QUIC

QUIC 的特徵

QUIC 主要的特徵包括:

  • 透過 UDP 的封包傳輸 (transfer protocol over UDP)
  • 支援 Connection 與 Stream
  • 可靠的資料傳輸 (reliable data transfers)
  • 流量控制 (flow control and congestion control)
  • 基於 TLS 1.3 的傳輸層加密與 1-RTT 連線建立 ( secure and transport handshakes)
  • 支援 0-RTT 快速交握 (fast handshakes and early data)

我們將依序介紹這些特徵。

透過 UDP 的封包傳輸

為了規避網路協定僵化的問題, QUIC 會把資料封裝成加密過的 UDP 封包來進行傳輸:

  • 對於中間經手的網路節點而言,它們只會看到一個個加密過的 UDP 封包,因此除了導傳外不會多做處理,藉此提升傳輸效能。
  • 對於請求與回應的兩端點而言,則需要在傳輸層負起重傳與錯誤處理等工作,藉此保證資料傳輸的可靠性。

支援 Connection 與 Stream

QUIC 提供了與 HTTP/2 一樣的 multiple streams over a single connection 的概念。差別在於:

  • HTTP/2 是傳輸層的 TCP connection + 應用層的 stream。
  • QUIC 是傳輸層同時提供了 connection 與 stream。

且由於 QUIC 是透過 UDP 來進行資料傳輸,因此它所提供的 connection 與 stream 皆是抽象邏輯,只存在於 client 與 sever 兩節點身上。

相較於 TCP 協定使用 TCP Socket 來建立連線,QUIC 則是採用 UDP Socket + QUIC connection。有別於 TCP socket 需要綁定用戶與伺服器兩端的 IP 與 port,QUIC connection 則是用特有的 connection ID 來辨認連線。

Connection ID

Connection ID 主要有 destination 與 source 兩種類別,都可以用來辨識接收到的 request 屬於哪一個連線。因此對於節點來說,它除了需要維護自身的 connection ID 與連線的對應外,也必須記錄所有連線對象的 connection ID 與連線的對應。

Connection ID Negotiation

本節將會解釋 client 與 server 如何在建立連線的過程中交換彼此的 connection ID,請搭配下圖服用:

Connection ID negotiation in QUIC
  1. Client 初始建立連線
    ・Client 會將自己的 connection ID 填入 request 的 source ID 欄位中。
    ・將 destination ID 填入一個隨機數字。
    ・發送 ClientHello。
  2. Server 收到來自 client 的連線建立請求
    ・Server 將 request 中的 source ID 保存在自己的 destination ID 清單中。
    ・在 response 的 source ID 欄位中填入自己的 connection ID。
    ・在 response 的 destination ID 欄位中填入對方的 connection ID。
    ・發送 ServerHello ,以通知 client 連線建立成功。
  3. Client 收到 ServerHello
    ・Client 將 response 中的 source ID 保存在自己的 destination ID 清單中。
    ・至此,雙方完成 connection ID 的交換。
  4. 進行一般的資料傳輸 (request/response)
    ・在進行一般的資料傳輸時,請求方只會在 request 中填入 destination ID 欄位,並不會攜帶 source ID 欄位。
    ・QUIC 的連線雙方,會預設對方可以辨識出連線,並用對應的 connection ID 來回應。
  5. Connection ID 的新增
    ・一個連線所用的 Connection ID 可以透過傳送 NEW_CONNECTION_ID 這個 frame 來新增。
    ・交換的過程與一開始的 connection ID 交換是相同的。

Connection Migration

由於 QUIC connection 不再綁定 IP 與 port,所以一個連線的生命週期,與clinet 及 server 的實體網路狀態無關。因此 QUIC 可以實現 TCP 所做不到的 connection migration,即允許雙方節點在不重建連線的情況下更換底層的網路環境。

Streams

QUIC stream 除了實作於傳輸層外,大致上的特性與 HTTP/2 的版本一致:

  • 對於同一個 Stream 內的資料,保證其請求與接受順序一致 (in-order delivery within streams)。
  • 對於不同 Stream 內的資料,不保證之間的順序 (out-of-order delivery between streams)
  • 提供雙向 (bidirectional) 與單向 (unidirectional) 兩種 stream 類別。

此外,也提供了 stream prioritizationstream state 等功能,用以控制資料傳輸的順序與流量。

可靠的資料傳輸

由於 QUIC 透過 UDP 來傳輸封包,因此資料的可靠性得仰賴 client 與 sever 兩節點。與 TCP 只提供 connection-level 的資料可靠性相比, QUIC 透過 stream state 的方式提供了 stream-level 的資料可靠性。因此不同stream 的資料重傳與錯誤處理將完全獨立。

流量控制

與資料可靠性相仿, QUIC 的流量控制也必須仰賴 client 與 sever 兩節點負責。QUIC 同時提供了 connection-level 與 stream-level 兩種層級的流量控制。

基於 TLS 1.3 的傳輸層加密與 1-RTT 交握

QUIC 並不提供明文(cleartext)的資料傳輸。且為了提升資料傳輸的安全性, QUIC 只支援 TLS 1.3 以上的傳輸層安全性協定。

TLS 1.2 vs TLS 1.3

除了保障資料傳輸的安全外,採用 TLS 1.3 的最大好處在於它只需要 1-RTT 便可以完成 TLS handshake。而 QUIC 也在進行 TLS handshake 的同時,順道完成整個 QUIC 連線的建立,整體包含 version negotiation、cryptographic 、transport handshake 與 TLS handshake。

相比於 HTTP + TLS 需要 3-RTT 的冗長連線建立過程,只需要 1-RTT 的 QUIC 大幅減少了連線建立的時間。

支援 0-RTT 快速交握

除了 1-RTT 交握模式外,QUIC 也支援了 0-RTT 的快速交握機制。 0-RTT 交握其實依舊需要進行1-RTT 的連線建立,但 client 可以在建立連線的同時,攜帶加密過的請求資料 (early data),server 則在回應連線建立成功的同時,回傳處理結果

Fast handshakes with early data

需要注意的是,0-RTT 交握並不是沒有使用上的限制。必須達成以下條件才能使用:

  • Client 與 server 必須曾經建立過連線。
  • 雙方必須還保有之前連線所使用的 PSKcertificate
  • Early data 必須用之前連線所用的金鑰加密。
  • Server 必須願意支援 0-RTT 快速交握 。由於快速交握必須在還未確認連線建立狀況的階段先行處理資料,除了額外的資源消耗,也有資安上的風險。

HTTP/2 vs HTTP/3

在介紹完 QUIC 的主要特徵後,接著來談談 HTTP/3 在行為與特徵上,與 HTTP/2 有什麼差別。大致上可以統整成下方的比較表:

HTTP/2 vs HTTP/3

HTTP/2 與 HTTP/3 的相同點

HTTP/2 與 HTTP/3 兩者皆支援:

  • 相同的 HTTP syntax 與 HTTP frame
  • Connection 與 stream 的概念
  • Stream multiplexing 與 stream prioritization
  • Stream-level 的 flow control 與 congestion control
  • TLS handshake 與 fast handshake
  • Server push
  • Head compression

HTTP/2 與 HTTP/3 的相異點

  • HTTP/2 的 stream 是實作在應用層,而 HTTP/3 則是實作於傳輸層。因此 HTTP/3 可以避免傳輸層的 HOL blocking 問題,並提供更細緻的 flow control 與 congestion control (應用層 vs 傳輸層)。
  • 以傳輸效率來看,HTTP/2 仰賴 TCP socket 進行資料傳輸, HTTP/3 則是透過 UDP Socket + user space 上的 QUIC 實作來達成。 HTTP/3 可以提供更為有效的資料傳輸
  • 以系統資源消耗的角度而言,由於 TCP 有著十幾年的演算法與 Kernal 的優化,甚至有硬體的支援。在面對同樣量級的請求時,目前基於 QUIC 的 HTTP/3 會比基於 TCP 的HTTP/2 消耗更多的系統資源
  • HTTP/3 不再提供明文的資料傳輸
  • HTTP/3 的連線建立比 HTTP/2 更為快速。且相比於 HTTP/2 所用的 TCP fast open,HTTP/3 所用的 TLS fast handshake 更為容易落地普及。
  • HTTP/2 使用 HPACK 來進行 header compression ,而 HTTP/3 則是採用QPACK
  • HTTP/3 支援 connection migration,對於行動網路環境的 client 更為友善

常見的批評與顧慮

HTTP/3 與 QUIC 常見的批評包括:

  • UDP will never work.
  • UDP is slow in kernels.
  • UDP is too easy to DDOS
  • QUIC takes too much CPU.
  • We are not Google.
  • Too small of an improvement.

可以從上發現大家在意的點著重於資安隱憂資源消耗

關於安全的部分,其實 QUIC 的規格書中有詳細說明要如何避免 UDP 常見的資安議題,也可以在 QUIC workgroup 的 mailing list 中找到非常多相關的討論,安全的議題是 QUIC workgroup 非常重視的一環,也是決定普及成敗的重要因素。因此,筆者相信最終版本的 QUIC 可以設計出完善的方案,以解釋目前對於 UDP 及 QUIC 的安全疑慮。

至於的資源消耗的問題,主要癥結在於長久以來網路的世界都被 TCP 所統治,效能優化也都是基於 TCP/ IP 的需求而發展。因此基於 UDP 的應用技術勢必會相對弱勢 。但只要 HTTP/3 能被逐漸採納,那相關的優化研究自然地會發展前進,因此這是個在未來預期可被解決的問題。透過 HTTP 這塊大旗來推廣 QUIC ,是 QUIC workgroup 所擬定的發展策略中,非常聰明的一手。


總結

在本文章中,我們談論了目前 HTTP/2 的缺點,並解釋了 HTTP/3 如何藉由採用 QUIC 這個新的傳輸層協定解決這些問題。此外,我們也介紹了 QUIC 的特徵與運作原理,並比較了 HTTP/2 與 HTTP/3 兩者間的差異。

總得來說, 基於 QUIC 的 HTTP/3 是個非常令人期待的技術發展。儘管有許多人並不看好 HTTP/3 ,認為它改進的幅度有限,也會像 IPv6 那樣曲高和寡。但 HTTP/3 之所以令人感到期待的並不純粹是因為功能上的改進,而是其背後所藏的巨大野心 — 醞釀一場顛覆主流 TCP/IP 架構的大革命。

可以預期 HTTP/3 與 QUIC 的實踐與普及,並不是近年內會發生的事。但作為如筆者般的開發工程師或網路技術愛好者,我們能做的便是分享與關注,且期盼它對網路技術與網路應用服務帶來更多的激盪與火花。

感謝大家的閱讀。如果有任何問題歡迎在下方留言討論。如果喜歡本文內容,也歡迎大家轉載並給予本文一些掌聲 (clap),謝謝。

參考資料

Jalex’s Murmur

If today was your last day and tomorrow was too late.

Chang Che-Pin

Written by

Jalex’s Murmur

If today was your last day and tomorrow was too late.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade