如何玩轉 HTTP 3?

如何玩轉 HTTP 3?

作者 | 阿文

出品 | CSDN(ID:CSDNnews)


超文本傳輸協議(HyperText Transfer Protocol)是一種用於分佈式、協作式和超媒體信息系統的應用層協議。自1990年代初以來,HTTP協議是整個Internet進行數據通信的基礎。

在 HTTP/1.0 中,每一個TCP請求或響應都會被分配一個新的連接,這就導致了連接啟動緩慢,在此之後,如何規避 TCP 啟動慢就一直是 HTTP協議改善的核心。此後,在HTTP/1.1中引入了keep-alive 的概念,其允許在同一個 TCP 連接中對多個請求或響應進行序列號,從而使得不需要為每個請求都設置新的連接,避免建立新連接帶來的網絡開銷。但是這個版本的keep-alive 連接不支持同時發送多個請求,隨著互聯網的迅猛發展又帶來了新的問題:如何讓數據發送效率提高?

在2015年,HTTP發佈了第二個版本,即HTTP/2,進行了重大更新。例如:

  • 在建立連接後,可以多路複用;
  • 在建立連接後,一次的請求與被響應,視為流;
  • 數據傳輸分為二進制幀片段。

而 HTTP/3是HTTP協議的第三個主要版本。在HTTP/3中,將棄用TCP協議,改為使用基於UDP協議的QUIC協議實現。實際上 HTTP/3 的前身是HTTP over QUIC,QUIC 是快速UDP網絡連接的簡稱,由Google公司研發,該協議旨在取代TCP協議,使網頁傳輸更快、更穩定、更安全。

2018年10月,互聯網工程任務組(IETF) HTTP和QUIC工作組主席Mark Nottingham提出了將HTTP-over-QUIC更名為HTTP/3,以區分其特點以及與Google 公司的QUIC的獨立性。


如何玩轉 HTTP 3?

為什麼使用UDP+QUIC?


實際上,在此前的HTTP協議中一直是使用TCP作為傳輸協議。為什麼在HTTP/3中要換成UDP呢?眾所周知,TCP 是一種面向連接的、可靠的、基於字節流的傳輸層通信協議,在數據傳輸過程中其加入了序列號、對收到的保溫進行排序以檢測重複數據,數據重傳、擁塞控制、使用校驗和確保無錯傳輸、流控制等。使用TCP 協議進行數據傳輸會經過三次握手,在連接創建過程中,很多參數要被初始化,例如序號被初始化以保證按序傳輸和連接的強壯性,其目的是保證數傳輸和斷開的可靠,確保所有數據都被完全傳輸。因此很多對業務穩定性非常高的協議都一直採用TCP協議作為數據傳輸協議。

TCP 報頭:

如何玩轉 HTTP 3?

事實上,在HTTP/2 之前的版本中,都是採用TCP 進行數據傳輸的。而 HTTP/2 引入的多路複用技術改善了HTTP/1.1的keep-alive 帶來的缺陷,但是當數據包丟失增加,HTTP/2的性能會由於TCP處理包重傳的方式(HOL阻塞)而下降,從而大大影響效率。因為所有的流都是共享同一個連接,當數據包丟失超出閾值,HTTP/2的運行效率可能還不如HTTP/1的效率高。

而UDP協議則比較簡單,其特點如下:

  • 無需建立連接,因此UDP不會引入建立連接的時延;
  • 沒有TCP 那麼複雜的報頭,例如重傳、序列號等等;
  • 速度快,但是不保證數據的完整性。

其報頭如下:

如何玩轉 HTTP 3?

那麼既然使用UDP進行數據傳輸如此不可靠,為什麼 HTTP/3 會使用UDP?

事實上,這與整個互聯網快速發展的大背景有關係。隨著移動互聯網快速發展以及物聯網以及5G技術的逐步興起,網絡交互的場景越來越豐富,大量的音頻、視頻、直播等數據在網絡傳上傳輸,用戶對網絡傳輸效率和 WEB 響應速度的要求也越來越高。HTTP/3 協議當然不能單獨使用UDP協議,它必須在QUIC的配合下才可以使用UDP,其把數據的完整性校驗這一環節放在了UDP協議之上,QUIC的特點:

減少了 TCP 三次握手及 TLS 握手時間,使用TCP協議配合HTTPS,TLS 完全握手需要至少 2 個 RTT 才能建立,簡化握手需要 1 個 RTT 的握手延遲,而QUIC在TLS握手時間上,由於建立在 UDP 的基礎上,同時又實現了 0RTT 的安全握手,所以在大部分情況下,只需要 0 個 RTT 就能實現數據發送。

改進的擁塞控制,QUIC 協議當前默認使用了 TCP 協議的 Cubic 擁塞控制算法,同時也支持 CubicBytes, Reno, RenoBytes, BBR, PCC 等擁塞控制算法。

避免隊頭阻塞的多路複用,隊頭阻塞主要是 TCP 協議的可靠性機制引入的。上面說了TCP為了實現可靠性,使用了很多機制來保障數據的傳輸,例如使用序列號來標識數據的順序,數據必須按照順序處理,如果前面的數據丟失,後面的數據就算到達了也不會通知應用層來處理。而QUIC使用UDP,沒有三次握手和連接,只需要用戶端和服務端的應用程序支持 QUIC 協議,完全避開了操作系統和中間設備的限制,同時相比此前的HTTP/2的多路複用,QUIC 一個連接上的多個流之間沒有依賴。這樣可以更快地並行處理任務。

比TCP協議更安全,TCP 協議的頭部沒有加密和認證,在傳輸過程中很容易被篡改,注入和竊聽。而 QUIC 除了個別報文比如 PUBLIC_RESET 和 CHLO,所有報文頭部都是經過認證的,報文 Body 都是經過加密的。

能夠連接遷移,什麼是連接遷移?比如使用手機從無線網切換到移動5G,這時客戶端的IP會改變,需要重新建立和服務端的 TCP 連接。而QUIC實現了任何一條 QUIC 連接不再以 IP 及端口進行標識,而是以一個 64 位的隨機數作為 ID 來標識,這樣當網絡變化,IP和端口改變,只要 ID 不變,這條連接依然維持著,上層業務邏輯感知不到變化,不會中斷,也就不需要重連。且由於這個ID是隨機的,產生衝突的概率非常小。

更科學的流量控制器,TCP 為了保證可靠性,窗口左邊沿向右滑動時的長度取決於已經確認的字節數。如果中間出現丟包,就算接收到了更大序號的 Segment,窗口也無法超過這個序列號。而QUIC 基於流和連接級別的流量控制,類似HTTP/2,通過window_update幀告訴對端自己可以接收的字節數,這樣發送方就不會發送超過這個數量的數據。通過BlockFrame告訴對端由於流量控制被阻塞了,無法發送數據。就算此前有些數據包沒有接收到,它的滑動只取決於接收到的最大偏移字節數。


如何玩轉 HTTP 3?

如何使用 HTTP/3?


好了,介紹了HTTP/3,那麼我們怎麼才能夠使用HTTP/3呢?事實上,現在很多雲廠商都實現了 HTTP/3,比如騰訊雲的負載均衡器、阿里雲的CDN服務、CloudFlare等等。那麼如果你是使用類似Nginx這樣的Web服務器如何使用HTTP/3呢?

以Nginx 為例,實際上,Nginx 在 2019 年 3 月 21 日公佈了 1.17.x 版本的路線圖,其中談到了支持 QUIC 和 HTTP/3 的計劃。但是至今,Nginx 已經發布了 1.17.8 的版本,在最新的1.17.8的 CHANGES 中也沒有發現HTTP/3的身影。估計如果希望原生的 Nginx 支持 HTTP/3 還需要繼續等待。

可喜的是邊緣計算廠商 CloudFlare 開源了 QUIC 的實現 quiche,使得 Nginx 提前支持 HTTP/3 ,quiche 項目地址: https://github.com/cloudflare/quiche/tree/master/extras/nginx 。

CloudFlare 已經成功在其CDN業務中實現了QUIC的部署,基於HTTP3 Quic的實現靠的就是他們開發的Quiche實現。

根據 quiche 的文檔,需要下載源碼和 Nginx 一同編譯,而因為需要 BoringSSL 以及 quiche 開發語言的不同,在編譯 Nginx 所需要的環境基礎上,還需要 cmake、rust、cargo、golang 等一系列工具的支持。

安裝步驟

1.下載的nginx並解壓,注意,這個補丁只支持1.16.x。

<code>curl -O https://nginx.org/download/nginx-1.16.1.tar.gz
tar xzvf nginx-1.16.1.tar.gz/<code>

2.克隆quiche:

<code>git clone --recursive https://github.com/cloudflare/quiche/<code>

3.使用patch將補丁引入:

<code>cd nginx-1.16.1
patch -p01 /<code>

4.構建nginx, 使其支持 HTTP/3:

<code>./configure                                 \\
       --prefix=$PWD                           \\
       --build="quiche-$(git --git-dir=../quiche/.git rev-parse --short HEAD)" \\
       --with-http_ssl_module                  \\
       --with-http_v2_module                   \\
       --with-http_v3_module                   \\
       --with-openssl=../quiche/deps/boringssl \\

       --with-quiche=../quiche/<code>

5.執行make:

<code>make/<code>

6.然後配置nginx的vhost,一個HTTP/3的配置如下:

<code>server {
  listen       80;
  # Enable HTTP/2 (optional).
  listen       443 ssl http2;
  # Enable QUIC and HTTP/3.
  listen 443 quic reuseport;

  server_name  www.awen.me;

  root   /vdata/www/default;
  index  index.html;

  ssl_certificate /usr/local/nginx/ssl/awen.me.crt;
  ssl_certificate_key /usr/local/nginx/ssl/awen.me.key;

  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers ……

  # Add Alt-Svc header to negotiate HTTP/3.
  add_header alt-svc 'h3-23=":443"; ma=86400';
  ……
}/<code>

更具體的配置和說明,可以參考官方文檔https://github.com/cloudflare/quiche/tree/master/extras/nginx。

QUIC 的實現原理是首先客戶端發起 tcp 連接判斷服務端響應頭是否有 alt-svc 頭,如有則嘗試使用 udp 443 去進行連接。因此,我們看到上面的配置中 add_header alt-svc 'h3-23=":443"; ma=86400';,客戶端請求類似如下:

如何玩轉 HTTP 3?

Alt-Svc 全稱為“Alternative-Service”,直譯為“備選服務”。該頭部列舉了當前站點備選的訪問方式列表。一般用於在提供 “QUIC” 等新興協議支持的同時,實現向下兼容。

h3-23=":443" 這部分內容定義了替代服務使用的協議、主機名和端口,其中主機名和端口可選,多個替代服務之間用英文逗號分隔。

ma 是 max-age 的縮寫,單位為秒。顯然,它表示瀏覽器在指定時間內,可以直接使用替代服務地址。

客戶端訪問

1.瀏覽器配置

以Chrome 為例進行配置,開啟 quic 的支持,chrome://flags 安裝如圖所示 Experimental QUIC protocol 設置為 enable 重啟瀏覽器:

如何玩轉 HTTP 3?

2.如何判斷QUIC是否已經生效?

第一種方法是安裝插件,在Chrome商店安裝 HTTP/2 and SPDY indicator,右上角有個閃電圖標會顯示 google 已經開啟 quic/43版本的支持。如圖所示:

如何玩轉 HTTP 3?

打開 chrome://net-internals/#quic 也可以看到當前使用 quic 協議的站點連接情況。第二種方式是通過wireshark抓包也可以看到QUIC的數據包。


分享到:


相關文章: