天天看點

圖解 | 為什麼HTTP3.0使用UDP協定

1. 大白和小黑

生活不止眼前的苟且,還有詩和遠方的田野。

新的一周又開始了,大白和小黑是同僚,平時倆人一起喝酒吃肉打遊戲居多,當然有時候也讨論下學術和前沿技術。

這不,小黑聽說了個新鮮玩意,然後和大白聊了起來:

小黑:大白大白,聽說HTTP協定已經到3.0了?
大白:是的,已經到3.0了,甚至我還要告訴你它還是基于UDP開發的!
小黑:UDP?沒搞錯吧?!UDP可是不靠譜代言人啊,TCP不香了嗎?
大白:千真萬确,而且已經跑起來效果不錯,正在推廣呢,據說Chrome金絲雀版本已經支援了,可以搶鮮試用。
小黑:害!我這個憨憨HTTP2.0還沒整明白,3.0就來了,快快快,給俺講講這個黑科技。
圖解 | 為什麼HTTP3.0使用UDP協定

小黑是個爽快人,許諾大白給他講清楚了,周五就請一頓木屋燒烤,再小酌幾杯,放松一下。

圖解 | 為什麼HTTP3.0使用UDP協定

大白看在小黑對知識的渴求和燒烤的份上,決定給小黑講講HTTP3.0和QUIC協定那些事。

通過本文你将了解到以下内容:

  • HTTP2.0和TCP存在的一些問題
  • QUIC協定為什麼選擇UDP
  • QUIC協定的重要特性
  • HTTP3.0和QUIC協定的前景和應用效果
圖解 | 為什麼HTTP3.0使用UDP協定

2.HTTP2.0和HTTP3.0

科技永不止步。

我們都知道網際網路中業務是不斷疊代前進的,像HTTP這種重要的網絡協定也是如此,新版本是對舊版本的揚棄。

2.1 HTTP2.0和TCP的愛恨糾葛

HTTP2.0是2015年推出的,還是比較年輕的,其重要的二進制分幀協定、多路複用、頭部壓縮、服務端推送等重要優化使HTTP協定真正上了一個新台階。

圖解 | 為什麼HTTP3.0使用UDP協定

像谷歌這種重要的公司并沒有滿足于此,而且想繼續提升HTTP的性能,花最少的時間和資源擷取極緻體驗。

那麼肯定要問HTTP2.0雖然性能已經不錯了,還有什麼不足嗎?

  • 建立連接配接時間長(本質上是TCP的問題)
  • 隊頭阻塞問題
  • 移動網際網路領域表現不佳(弱網環境)
  • ......

熟悉HTTP2.0協定的同學應該知道,這些缺點基本都是由于TCP協定引起的,水能載舟亦能覆舟,其實TCP也很無辜呀!

圖解 | 為什麼HTTP3.0使用UDP協定

在我們眼裡,TCP是面向連接配接、可靠的傳輸層協定,目前幾乎所有重要的協定和應用都是基于TCP來實作的。

網絡環境的改變速度很快,但是TCP協定相對緩慢,正是這種沖突促使谷歌做出了一個看似出乎意料的決定-基于UDP來開發新一代HTTP協定。

2.2 谷歌為什麼選擇UDP

上文提到,谷歌選擇UDP是看似出乎意料的,仔細想一想其實很有道理。

我們單純地看看TCP協定的不足和UDP的一些優點:

  • 基于TCP開發的裝置和協定非常多,相容困難
  • TCP協定棧是Linux内部的重要部分,修改和更新成本很大
  • UDP本身是無連接配接的、沒有建鍊和拆鍊成本
  • UDP的資料包無隊頭阻塞問題
  • UDP改造成本小

從上面的對比可以知道,谷歌要想從TCP上進行改造更新絕非易事,但是UDP雖然沒有TCP為了保證可靠連接配接而引發的問題,但是UDP本身不可靠,又不能直接用。

圖解 | 為什麼HTTP3.0使用UDP協定

綜合而知,谷歌決定在UDP基礎上改造一個具備TCP協定優點的新協定也就順理成章了,這個新協定就是QUIC協定。

2.3 QUIC協定和HTTP3.0

QUIC其實是Quick UDP Internet Connections的縮寫,直譯為快速UDP網際網路連接配接。

圖解 | 為什麼HTTP3.0使用UDP協定

我們來看看維基百科對于QUIC協定的一些介紹:

QUIC協定最初由Google的Jim Roskind設計,實施并于2012年部署,在2013年随着實驗的擴大而公開宣布,并向IETF進行了描述。
QUIC提高了目前正在使用TCP的面向連接配接的Web應用程式的性能。它在兩個端點之間使用使用者資料報協定(UDP)建立多個複用連接配接來實作此目的。
QUIC的次要目标包括減少連接配接和傳輸延遲,在每個方向進行帶寬估計以避免擁塞。它還将擁塞控制算法移動到使用者空間,而不是核心空間,此外使用前向糾錯(FEC)進行擴充,以在出現錯誤時進一步提高性能。

HTTP3.0又稱為HTTP Over QUIC,其棄用TCP協定,改為使用基于UDP協定的QUIC協定來實作。

圖解 | 為什麼HTTP3.0使用UDP協定

3. QUIC協定詳解

擇其善者而從之,其不善者而改之。

HTTP3.0既然選擇了QUIC協定,也就意味着HTTP3.0基本繼承了HTTP2.0的強大功能,并且進一步解決了HTTP2.0存在的一些問題,同時必然引入了新的問題。

圖解 | 為什麼HTTP3.0使用UDP協定

QUIC協定必須要實作HTTP2.0在TCP協定上的重要功能,同時解決遺留問題,我們來看看QUIC是如何實作的。

3.1 隊頭阻塞問題

隊頭阻塞 Head-of-line blocking(縮寫為HOL blocking)是計算機網絡中是一種性能受限的現象,通俗來說就是:一個資料包影響了一堆資料包,它不來大家都走不了。

隊頭阻塞問題可能存在于HTTP層和TCP層,在HTTP1.x時兩個層次都存在該問題。

圖解 | 為什麼HTTP3.0使用UDP協定

HTTP2.0協定的多路複用機制解決了HTTP層的隊頭阻塞問題,但是在TCP層仍然存在隊頭阻塞問題。

TCP協定在收到資料包之後,這部分資料可能是亂序到達的,但是TCP必須将所有資料收集排序整合後給上層使用,如果其中某個包丢失了,就必須等待重傳,進而出現某個丢包資料阻塞整個連接配接的資料使用。

QUIC協定是基于UDP協定實作的,在一條連結上可以有多個流,流與流之間是互不影響的,當一個流出現丢包影響範圍非常小,進而解決隊頭阻塞問題。

3.2 0RTT 建鍊

衡量網絡建鍊的常用名額是RTT Round-Trip Time,也就是資料包一來一回的時間消耗。

圖解 | 為什麼HTTP3.0使用UDP協定

RTT包括三部分:往返傳播時延、網絡裝置内排隊時延、應用程式資料處理時延。

圖解 | 為什麼HTTP3.0使用UDP協定

一般來說HTTPS協定要建立完整連結包括:TCP握手和TLS握手,總計需要至少2-3個RTT,普通的HTTP協定也需要至少1個RTT才可以完成握手。

然而,QUIC協定可以實作在第一個包就可以包含有效的應用資料,進而實作0RTT,但這也是有條件的。

圖解 | 為什麼HTTP3.0使用UDP協定

簡單來說,基于TCP協定和TLS協定的HTTP2.0在真正發送資料包之前需要花費一些時間來完成握手和加密協商,完成之後才可以真正傳輸業務資料。

但是QUIC則第一個資料包就可以發業務資料,進而在連接配接延時有很大優勢,可以節約數百毫秒的時間。

圖解 | 為什麼HTTP3.0使用UDP協定

QUIC的0RTT也是需要條件的,對于第一次互動的用戶端和服務端0RTT也是做不到的,畢竟雙方完全陌生。

是以,QUIC協定可以分為首次連接配接和非首次連接配接,兩種情況進行讨論。

3.3 首次連接配接和非首次連接配接

使用QUIC協定的用戶端和服務端要使用1RTT進行密鑰交換,使用的交換算法是DH(Diffie-Hellman)迪菲-赫爾曼算法。

DH算法開辟了密鑰交換的新思路,在之前的文章中提到的RSA算法也是基于這種思想實作的,但是DH算法和RSA的密鑰交換不完全一樣,感興趣的讀者可以看看DH算法的數學原理。

DH算法開辟了密鑰交換的新思路,在之前的文章中提到的RSA算法也是基于這種思想實作的,但是DH算法和RSA的密鑰交換不完全一樣,感興趣的讀者可以看看DH算法的數學原理。

3.3.1 首次連接配接

簡單來說一下,首次連接配接時用戶端和服務端的密鑰協商和資料傳輸過程,其中涉及了DH算法的基本過程:

  1. 用戶端對于首次連接配接的服務端先發送client hello請求。
  2. 服務端生成一個素數p和一個整數g,同時生成一個随機數 (筆誤-此處應該是Ks_pri)為私鑰,然後計算出公鑰 = mod p,服務端将,p,g三個元素打包稱為config,後續發送給用戶端。
  3. 用戶端随機生成一個自己的私鑰,再從config中讀取g和p,計算用戶端公鑰 = mod p。
  4. 用戶端使用自己的私鑰和服務端發來的config中讀取的服務端公鑰,生成後續資料加密用的密鑰K = mod p。
  5. 用戶端使用密鑰K加密業務資料,并追加自己的公鑰,都傳遞給服務端。
  6. 服務端根據自己的私鑰和用戶端公鑰生成用戶端加密用的密鑰K = mod p。
  7. 為了保證資料安全,上述生成的密鑰K隻會生成使用1次,後續服務端會按照相同的規則生成一套全新的公鑰和私鑰,并使用這組公私鑰生成新的密鑰M。
  8. 服務端将新公鑰和新密鑰M加密的資料發給用戶端,用戶端根據新的服務端公鑰和自己原來的私鑰計算出本次的密鑰M,進行解密。
  9. 之後的用戶端和服務端資料互動都使用密鑰M來完成,密鑰K隻使用1次。
圖解 | 為什麼HTTP3.0使用UDP協定

3.3.2 非首次連接配接

前面提到用戶端和服務端首次連接配接時服務端傳遞了config包,裡面包含了服務端公鑰和兩個随機數,用戶端會将config存儲下來,後續再連接配接時可以直接使用,進而跳過這個1RTT,實作0RTT的業務資料互動。

用戶端儲存config是有時間期限的,在config失效之後仍然需要進行首次連接配接時的密鑰交換。

3.4 前向安全問題

前向安全是密碼學領域的專業術語,看下百度上的解釋:

前向安全或前向保密Forward Secrecy是密碼學中通訊協定的安全屬性,指的是長期使用的主密鑰洩漏不會導緻過去的會話密鑰洩漏。
前向安全能夠保護過去進行的通訊不受密碼或密鑰在未來暴露的威脅,如果系統具有前向安全性,就可以保證在主密鑰洩露時曆史通訊的安全,即使系統遭到主動攻擊也是如此。

通俗來說,前向安全指的是密鑰洩漏也不會讓之前加密的資料被洩漏,影響的隻有目前,對之前的資料無影響。

前面提到QUIC協定首次連接配接時先後生成了兩個加密密鑰,由于config被用戶端存儲了,如果期間服務端私鑰洩漏,那麼可以根據K = mod p計算出密鑰K。

如果一直使用這個密鑰進行加解密,那麼就可以用K解密所有曆史消息,是以後續又生成了新密鑰,使用其進行加解密,當時完成互動時則銷毀,進而實作了前向安全。

圖解 | 為什麼HTTP3.0使用UDP協定

3.5 前向糾錯

前向糾錯是通信領域的術語,看下百科的解釋:

前向糾錯也叫前向糾錯碼Forward Error Correction 簡稱FEC 是增加資料通訊可信度的方法,在單向通訊信道中,一旦錯誤被發現,其接收器将無權再請求傳輸。
FEC 是利用資料進行傳輸備援資訊的方法,當傳輸中出現錯誤,将允許接收器再建資料。

聽這段描述就是做校驗的,看看QUIC協定是如何實作的:

QUIC每發送一組資料就對這組資料進行異或運算,并将結果作為一個FEC包發送出去,接收方收到這一組資料後根據資料包和FEC包即可進行校驗和糾錯。

3.6 連接配接遷移

網絡切換幾乎無時無刻不在發生。

TCP協定使用五元組來表示一條唯一的連接配接,當我們從4G環境切換到wifi環境時,手機的IP位址就會發生變化,這時必須建立新的TCP連接配接才能繼續傳輸資料。

QUIC協定基于UDP實作摒棄了五元組的概念,使用64位的随機數作為連接配接的ID,并使用該ID表示連接配接。

基于QUIC協定之下,我們在日常wifi和4G切換時,或者不同基站之間切換都不會重連,進而提高業務層的體驗。

圖解 | 為什麼HTTP3.0使用UDP協定

4. QUIC的應用和前景

通過前面的一些介紹我們看出來QUIC協定雖然是基于UDP來實作的,但是它将TCP的重要功能都進行了實作和優化,否則使用者是不會買賬的。

QUIC協定的核心思想是将TCP協定在核心實作的諸如可靠傳輸、流量控制、擁塞控制等功能轉移到使用者态來實作,同時在加密傳輸方向的嘗試也推動了TLS1.3的發展。

但是TCP協定的勢力過于強大,很多網絡裝置甚至對于UDP資料包做了很多不友好的政策,進行攔截進而導緻成功連接配接率下降。

主導者谷歌在自家産品做了很多嘗試,國内騰訊公司也做了很多關于QUIC協定的嘗試。

其中騰訊雲對QUIC協定表現了很大的興趣,并做了一些優化然後在一些重點産品中對連接配接遷移、QUIC成功率、弱網環境耗時等進行了實驗,給出了來自生産環境的諸多寶貴資料。

簡單看一組騰訊雲在移動網際網路場景下的不同丢包率下的請求耗時分布:

圖解 | 為什麼HTTP3.0使用UDP協定
圖解 | 為什麼HTTP3.0使用UDP協定

任何新生事物的推動都是需要時間的,出現多年的HTTP2.0和HTTPS協定的普及度都沒有預想高,IPv6也是如此,不過QUIC已經展現了強大的生命力,讓我們拭目以待吧!

5.本文小結

網絡協定本身就很複雜,本文隻能從整體出發對重要的部分做粗淺的闡述,如果對某個點很感興趣,可以查閱相關代碼和RFC文檔。

我們之前可能遇到過這個面試題:

如何用UDP協定來實作TCP協定的主要功能。

我确實筆試遇到過這道題,可以說很抓狂,題目太宏大了。