QUIC/HTTP3 協議簡析


從 HTTP 的進化歷史講起,細說使用協議的變遷,了解原因發現問題,解碼 QUIC 在 HTTP3 中的支撐作用,共同探討 HTTP3 的未來。

HTTP、HTTP2 和 HTTP3

先和大家來回顧一下 HTTP 的歷史,看看 HTTP3 相比 HTTP、HTTP2 都有哪些改進和升級的地方。

HTTP VS HTTP2

HTTP 和 HTTP2 的差別

多路復用:多路復用時,多文件傳輸有時只需維護一個 TCP 連接。如果是 HTTP1 協議下,每份資源的傳輸對應一個 TCP 連接,一般最多只能開啟 6 個 TCP 連接來傳輸多路數據,后續每增加一個新鏈接就會因為擁堵問題卡死,進而導致整個進程無法運行。因此HTTP/2解決了 HTTP 的隊頭阻塞問題。

頭部壓縮和 Server Push:HTTP2 會通過 HPACK 做頭部壓縮。同時 HTTP2 是二進制協議,在解析上相比基於文本的 HTTP解析效率上有所提升,並且 HTTP2 還增加了 Server Push。

在 TCP 下,依然無法解決延遲問題,比如為防止初始阻塞而引入的慢啟動;TCP 隊頭阻塞,比如由於發生丟包,整個連接涉及的傳輸數據都需要重傳而引起的阻塞。

盡管 HTTP2 相比 HTTP 已經有了改進的地方,但是如果你有 2% 的丟包率,那 HTTP2 在性能上就沒有優勢了。

上圖是造成 TCP 隊頭擁塞(Head of line blocking)的原因。HTTP2 協議是基於 TCP 的,但是 TCP 本身是無法解決隊頭擁塞,為什么呢?因為 HTTP2 會把一次傳輸所有的文件都放在一個 TCP 連接中,只要這個 TCP 中發生一個丟包,連接就必須重新建立,之前所有傳輸內容進行必須重傳,從而造成擁塞。

HTTP3 VS HTTP2

  • HTTP3 本質不是對 HTTP 協議本身的改進,它主要是集中在如何提高傳輸效率。上圖是相比 HTTP2 而言 HTTP3 提升的點:

  • HTTP3 使用 stream 進一步擴展了 HTTP2 的多路復用。在 HTTP3 模式下,一般傳輸多少個文件就會產生對應數量的 stream。當這些文件中的其中一個發生丟包時,你只需要重傳丟包文件的對應 stream 即可。

  • HTTP3 不再是基於 TCP 建立的,而是通過 UDP 建立,在用戶空間保證傳輸的可靠性,相比 TCP,UDP 之上的 QUIC 協議提高了連接建立的速度,降低了延遲。

  • 通過引入 Connection ID,使得 HTTP3 支持連接遷移以及 NAT 的重綁定。

  • HTTP3 含有一個包括驗證、加密、數據及負載的 built-in 的TLS安全機制。

  • 擁塞控制。TCP 是在內核區實現的,而 HTTP3 將擁塞控制移出了內核,通過用戶空間來實現。這樣做的好處就是不再需要等待內核更新可以實現很方便的進行快速迭代。

  • 頭部壓縮。HTTP2 使用的 HPACK,HTTP3 更換成了兼容 HPACK 的 QPACK 壓縮方案。QPACK 優化了對亂序發送的支持,也優化了壓縮率。

為什么選擇 QUIC

從圖上可以看到 QUIC 協議層就實現了可靠的數據傳輸,擁塞控制,加密,多路數據流。

至於 QUIC 為什么使用了 UDP 的問題,在了解這個之前,我們需要先知道一個事情。頻繁的用戶態和核心態切換會效率問題。理論上說,將應用層的東西遷移到內核從而提升效率是可行的,但是這么做會影響操作系統的穩定性。另一方面,我們可以選擇將這部分內容遷移到用戶空間。比如目前流行的 DPDK,當網卡將數據包傳輸過來時,它是繞過內核在用戶空間進行控制和應用。目前又拍雲的 DNS 就進行了這樣的處理,讓又拍雲的整體效率提升了5-10 倍。

接下來我們來正式說一下 QUIC 為什么使用了 UDP 的問題,是因為以下幾點:

  • 避免 ossification(僵化):QUIC 協議加密負載,也是避免協議僵化一種方式,比如當中間層處理 UDP 數據時,只需要按照數據包的方式去處理即可,不需要去關注內部層的具體信息。

  • 放棄改進 TCP 本身

  • 創新方向:QUIC 是由谷歌提出的,所以 UDP 是以瀏覽器為出發點,從協議、從瀏覽器方向來進行創新。

TLS 1.3 Vs TLS 1.2

TLS 1.3 跟 1.2 的一些提升主要有上圖幾點,大家可以大致看一下:

  • TLS 1.3 采用了新的加密套件

  • TLS 1.3 定義了一些新的證書類型以及秘鑰交換機制。在 TLS 1.3 你不再需要去特別指定,它可以根據秘鑰套件配件進行證書類型的自主推導。

QUIC 存在的問題

接下來說一下 QUIC 目前存在的問題。

首先是因為這些年性能的優化提升都針對 TCP ,使得 UDP 性能沒有任何改進。當然隨着 QUIC3 的發布,相信后續應該會有相對的投入。

其次是安全問題,也就是反射攻擊,即偽造原地址。這個指發送數據包時的原地址是偽造的,不是真正的地址,會引起放大攻擊。原因是 QUIC 握手過程是不對稱的,特別是第一次請求時,客戶端只需要發送幾個字節的信息到服務器,而服務器則需要把證書等很多東西返還給客戶端,這個不對稱的機會造成了放大。草案 27 定義了兩個規則和機制來限制反射攻擊:客戶端發送Initial包,即第一個數據包時,其長度必須在 1200 bytes以上,不足部分用 Padding 幀填充,同時,當服務端不確定客戶端可靠性時,可以發送 Retry 包要求客戶端再次提供驗證信息。

開源 QUIC 的實現

接下來我們簡單說一下目前開源的使用情況:

  • quiche:這個是用 Rust 做的庫,通過 Nginx 調用。google 自己的庫也叫 quiche,C++寫的。

  • ATS:Apache Traffic Server

  • golang:Caddy;

  • python+C,aioquic

  • 微軟msquic

開源 QUIC 的實現有很多,上面只是其中的一部分,同時我選擇了quiche 和 aioquic 做了一些簡單測試。

上圖展示的是從 cloudflare 提供支持 HTTP3 的 curl ,可以看到這個返回的值就是 HTTP/3 200。其中 alternative service 段,指示為 h3—27,表示支持 http3 draft-27 的服務跑在 UDP 443 端口。這個 alt-svc 是 HTTP2 時代就存在,在 HTTP3 也持續使用,因為有些時候瀏覽器並不知道服務器是否支持 QUIC,所以通過 TCP 發起請求,確定有 H3 支持后,再通過 UDP連接。

這個是 HTTP2 的,目前可能是因為本身庫的問題,使用 curl 打不開谷歌,但是從信息上可以看到 27、25 這些都是支持的。

如何部署以及達成 HTTP3 的 QUIC 實現

目前主要有兩種方式來實現,一種是代理,第二種是通過 Nginx。

騰訊是通過整合到 Nginx 利用它來實現框架的。同時因為 QUIC 每一條請求的含有頭的數據都會經過加密,騰訊有一個單獨的硬件加密群,如果你使用騰訊,那么你所有的加解密都會通過他們的硬件來加速。

從騰訊這個可以看出加解密部分有着很可觀的 CPU 占用率,如果后續所有的請求都是通過 HTTP3 來進行的話,在提升這塊占用率上需要未雨綢繆。當然就像前面提到的 DPDK,也就是把數據丟到 FPGA 內去加解密是一個可以考慮的解決方案。

通過代理來實現的這種方式,目前官方暫時還沒有消息。我可以像 cloudflare 那樣,先在外面進行整合,然后再講整合鏈接轉到 Nginx 內。

又拍雲目前有 LBS 和 Marco ,這個是因為 LBS 只認 TCP/UDP,它看不到 HTTP。也就是我們做了一個負載均衡的集群,通過這個集群在轉到 Nginx 上。而使用 UDP 則相當於已經走過了一個四層的負載均衡,那么后續可以嘗試將 QUIC 的基線提取出來使用,在代理上做加解密,從而提高效率。

往期技術文章都在微信同步分享,可以添加微信:upyun0001.png

推薦閱讀

容器化技術在數據中心的實踐

從新冠疫情出發,漫談 Gossip 協議


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM