文/Geoff Huston (APNIC首席科學家)
快速UDP互聯網連接(QUIC)是一種網絡協議,最初由谷歌公司開發和部署,最近(2021年5月)在互聯網工程任務組(IETF)中被標準化(標準文檔RFC 9000)。
QUIC并不是一個最近才被提出的協議,它是由谷歌在2012年開發,并在2013年8月發布的第29版Chromium瀏覽器中包含了最初的公開版本。QUIC的誕生初衷是試圖完善互聯網協議(IP)中傳輸控制協議(TCP)的基本操作,并非想從根本上改變流控制程序和流管理,而是通過改變傳輸功能在終端主機內的實現位置,從而改變該功能的變更控制者。
互聯網協議中的TCP協議已經被實現為操作系統的底層功能。應用程序通過接口與TCP交互,實現I/O(輸入/輸出)操作的基本開/關和讀/寫功能。數據流完整性和流控制的細節也在很大程度上對應用程序是隱藏透明的。這些內容當然使得應用的操作變得更簡單,但這種簡單性也伴隨著其自身的問題。
TCP有它自身的問題,在基于網絡(Web)的服務方面尤其如此。如今,大多數網頁都不是簡單的單體對象。它們通常包含許多獨立的組件,包括圖像、腳本、自定義框架、樣式表等等。其中每一個組件都是獨立的對象。如果使用配備了原始HTTP實現的瀏覽器,即使它們是從同一個IP地址獲取資源,每個對象也都將在一個新的TCP會話中被加載。為復合型網絡資源中每個不同的網絡對象建立一個新的TCP會話和一個新的傳輸層安全(TLS)會話的開銷可能會變得非常大,而復用已經建立的TLS會話從同一服務器上多次獲取資源則變得十分有吸引力。
但是這種在單個TCP會話中復用若干數據流的方法也有其問題。在單個會話中復用多個邏輯數據流會在流處理器之間產生不必要的相互依賴,并可能導致線頭阻塞的情況,即當前活動流的傳輸停滯會阻塞同一TCP會話中其他所有排隊獲取的流。因此結論是,如果我們想通過在協議中引進并行行為來提高這種復合型連接的效率,那么我們就需要現有TCP以外的實現方式。
當然,這聽起來比實際情況要簡單得多。一些類別的應用程序和服務的開發者希望看到TCP行為的改變,但實現這些變化取決于操作系統平臺的維護者。這種成本和收益的轉移往往會導致一種僵局,即對于那些需要進行這種改變的人來說,改變的動機是不充分的。通過允許應用程序直接控制其自身希望的傳輸服務行為方式,可以獲得更直接的結果。
這就是用戶數據報協議(UDP)發揮作用的地方。UDP是一個狹窄的“墊片”協議,使得應用程序可以直接控制IP層的基本數據報行為。一個應用程序可以實現自己的端到端傳輸協議,并加載該傳輸協議的控制結構及其有效載荷,并將兩者進行組合作為UDP有效載荷。在這一點上,應用程序對傳輸協議有完全的控制權,可以按照自己的意愿定制傳輸協議的行為,而無需等待任何第三方。
QUIC是一種端到端傳輸協議,基于UDP數據報流實現,如圖1所示。

圖1 TCP和QUIC在HTTP架構中的比較
QUIC采用了TCP的流完整性和流控制功能的組合,將其與TLS的會話加密功能相結合,實現了更靈活的多流處理版本,還增加了對地址敏捷性的更好支持,以容忍各種各樣的網絡地址轉換(NAT)行為。
為了方便地穿透NAT,QUIC實現了連接標識符(connection IDs)。每個端點都會生成連接標識符,使得收到的帶有該連接標識符的數據包被路由到使用該連接標識符的進程。在QUIC版本協商期間,這些連接標識符被交換,此后每個發送的QUIC數據包都包含遠端當前使用的連接標識符。
這種連接到端點的身份(連接標識符)與QUIC使用的IP地址和端口號之間的語義區分形式類似于主機身份協議(HIP)。QUIC的固定端點標識符允許會話在端點IP地址和端口的變化中持續存活。如果一個傳入的QUIC數據包使用相同的連接標識符,即使源IP地址和UDP端口號可能已經改變,也可以被識別為現有流的一部分。
一個QUIC會話可以支持多個流配置。雙向流將客戶端和服務器事務放入一個匹配的上下文中,例如HTTP/1的傳統請求/響應事務就需要這樣。客戶端將被期望與服務器打開一個雙向流,然后在流中發出一個請求,同時從服務器產生一個匹配的響應。服務器有可能向客戶端發起一個雙向的推送流,其中包含一個沒有初始請求的響應。控制信息是使用單向控制流傳輸的,其中一方可以在有需要的情況下向另一方傳遞信息。用于支持控制流的底層單向流接口也向應用程序公開。
QUIC不僅可以支持許多不同的流配置,而且可以在一個端到端的QUIC會話中支持不同的流配置。當然,這不是一個新的概念,HTTP/2協議就是一個很好的例子。它是一個應用層協議,增加了多路復用和流框架,以便在一個單一的傳輸數據流中攜帶多個數據流。然而,HTTP/2使用的單一TCP傳輸流可能會遇到線頭阻塞的問題,即所有疊加數據流在單一TCP會話中“命運共享”。如果其中一個數據流傳輸停滯,那么所有的疊加數據流都可能受到影響,也可能停滯。
QUIC提供一種略微不同的復用方法,其中每個疊加數據流可以使用自己的端到端流量狀態,一個疊加流的暫停并不意味著任何其他同步流受到影響。
在HTTP/2中,在相同的兩個端點之間復用多個數據流的部分原因是為了減少為每個TCP會話設置TLS安全關聯的開銷。當單個數據流各自發送一個小對象時,這可能是一個主要問題,而且有可能遇到這樣的情況:復合型網絡對象獲取的TCP和TLS握手部分占據了大部分的總下載時間和數據量。
QUIC將安全關聯作為利用UDP數據流實現的端到端狀態,由于它們基本上重復使用已建立的安全會話狀態,因此可以以非常輕量級的方式啟動單個數據流。
從以上對于TLS的提及可以看出,QUIC使用了端到端加密。這種加密是在UDP有效載荷上進行的,因此一旦TLS握手完成,隨后的QUIC數據包交換中只有很少的內容是明文的,如圖2所示。

圖2 TCP和TLS與QUIC的比較
QUIC中暴露的是公共標志(public flags)。QUIC數據包的這一初始部分由連接標識符組成,允許接收方將數據包與端點關聯起來,而無需解密整個數據包。QUIC版本(version)也是公共標志的一部分。這在最初的QUIC會話建立中使用,此后可以被省略。
QUIC數據包的其余部分是私有標志(private flags)和有效載荷(payload)。這些數據都是加密的,不能被竊聽者直接看到原始數據。私有標志包括數據包的序列號(sequence number),這個字段用于檢測重復和丟失的數據包。它還包括所有流量的控制參數,包括窗口廣告(window advertisements)。
以上是TCP和QUIC之間的關鍵區別之一。在TCP中,協議的控制部分是明確的,因此鏈路中的網絡設備能夠檢查端口地址并推斷應用類型,以及檢查連接的流狀態。即使只分析一部分TCP連接中單向流動的數據包,網絡設備也能推斷出相關的傳輸往返時間(round-trip time)和數據傳輸率。而且,類似NAT,操縱ACK(確認字符)流中的接收窗口(receive window)將允許網絡設備對連接進行流量控制,并以一種雙方都無法感知到的方式降低傳輸速率。將所有這些控制信息放在QUIC數據包的加密部分,可以確保沒有中間網絡設備直接看到這些信息,也沒有網絡設備對連接流進行操控。
大家可以認為:QUIC執行的是20世紀80年代假設的一個觀點。這就是,端到端傳輸協議不與網絡共享。網絡“看到”的都是無狀態的數據報,而終端可以安全地認為端到端傳輸控制字段中包含的信息是以保護其不受第三方審查和改變的方式在網絡上進行傳輸的。
簡短的回答是不!QUIC數據包是不能被分片的。實現這一目標的方法是讓QUIC HELLO數據包被填充到最大數據包尺寸。如果最大尺寸的數據包被分片,那么最初的HELLO交換則無法完成。允許的最大數據包尺寸至少是1200字節。如果端點通過某種路徑MTU發現程序確認了設置的可行性,則允許端點使用更大尺寸的最大數據包。
現在讓我們轉向測量QUIC和HTTP/3在現今互聯網中使用情況的任務。為了實現這一點,我們已經使用了APNIC實驗室的測量平臺,其中的測量任務被嵌入到在線廣告的腳本中。該廣告腳本引導用戶執行一些URL獲取操作,并對提供參考對象的服務器進行探測,以便從服務器的響應推斷出客戶端的能力和行為。
在這種情況下,客戶端被指示加載一個基本的URL對象(一個最小的1×1像素的“斑點”),其中URL的域名部分對每個單獨的測量是唯一的。為了建立一個QUIC測量,我們采取了以下步驟。
使用了支持QUIC的nginx服務器v1.12.7。
使用了一個具有HTTPS RR類型DNS記錄的URL域名,其值為alpn="h3"。
在內容上使用了一個替代服務指示,即Alt-Svc: h3=":443",其目的是引導客戶端使用HTTP/3進行后續資源獲取。
通常情況下,最后一個步驟即替代服務(Alt-Svc)指示,基本上是無效的。每個客戶端都是作為一個單一的事件來接收廣告的,腳本指示每個廣告加載一次,所以客戶端不應該對URL進行第二次加載。在這種情況下,我們對腳本進行了修改,指示客戶端等待兩秒,然后重復加載這個URL。假設這種延遲的重復足以讓客戶端對Alt-Svc指令采取行動。
在這個實驗中,我們有五分之一的時間執行這種重復的URL獲取。
QUIC測量開始于2022年6月初。在這個測量中,我們同時測量了查詢HTTPS記錄的用戶數量和使用HTTP/3(QUIC)訪問URL的用戶數量。該測量結果顯示在圖3中。

圖3 2022年6月的QUIC測量結果
有趣的是,查詢HTTPS DNS類型的用戶數量在10%~15%之間,而使用HTTP/3進行資源獲取的用戶數量則低得多,只有1.5%的用戶。如果客戶端瀏覽器支持HTTP/3,而且也被配置為查詢這種DNS記錄類型,那么為什么使用HTTP/3的后續訪問會更低?我們以后再來討論這個問題。
查看每個經濟體使用HTTP/3用于資源獲取的分布情況也很有意思,如圖4所示。

圖4 每個經濟體的QUIC使用情況
在丹麥、瑞典、挪威和瑞士,QUIC的使用率較高,而在亞洲、南美洲和非洲的大部分地區則較低。
哪些用戶使用HTTP/3?
通過使用每次HTTP獲取中提供的瀏覽器字符串,并將其與使用的協議(HTTP/2或HTTP/3)相匹配,我們可以獲得一個關于哪些平臺和瀏覽器使用HTTP/3進行對象獲取的概況(見表1)。應該注意的是,瀏覽器字符串作為一個數據源并不完全可靠,存在誤差,但其提供了一個相對可接受的結果,即哪些瀏覽器和哪些平臺正在使用HTTP/3進行資源獲取。

表1 系統平臺使用HTTP/3的分布情況
為了比較,表1還提供了沒有使用QUIC的系統平臺分布。很明顯,這里的主要變化是較多的蘋果iOS設備(iPhone和iPad)使用了HTTP/3。
瀏覽器對于HTTP/3的使用分布情況見表2。

表2 瀏覽器使用HTTP/3的分布情況
同樣,表2中與QUIC是否啟用存在主要差異是Safari瀏覽器,這與表1中的iOS平臺表現一致。
在這個階段,似乎在今天的互聯網中觀察到的對于HTTP/3和QUIC的使用,有接近一半是由iOS平臺和Safari瀏覽器貢獻的。
正如標準文檔RFC 9000所指出的:“UDP數據報不得在IP層被分割”。其還強調:“客戶端必須確保包含初始數據包的UDP數據報的UDP有效載荷至少為1200字節,必要時可以增加PADDING(填充)幀”。這意味著QUIC的實施必須將最大數據包的尺寸限制在一個保守的數值,以避免路徑分片的發生。
對這些限制的一種處理方式是使用某種形式的路徑MTU發現程序并使用發現的最大數據包的尺寸。另一種方法是選擇一個數據包的尺寸,確保不會存在被分片的情況。
為了回答目前QUIC使用的最大數據包尺寸的問題,我們觀察了每個QUIC會話并記錄了最大數據包尺寸。圖5展示了觀察到的數據包尺寸的分布。

圖5 QUIC最大數據包尺寸的分布
最常見的會話數據包尺寸是1200字節(46%的會話)。其次最常見的尺寸是1250字節(18.5%的會話)和1252字節(16.4%的會話)。沒有一個會話的數據包尺寸超過1357字節。
互聯網上的每個新協議都有一個與現有中間件(網絡中的中間設備)有關的潛在問題。許多數據包過濾器在可接受協議和端口的指定范圍內運行,使用UDP 443端口的加密有效載荷也不例外。因此,了解互聯網中QUIC協議的健壯程度是合乎情理的。
如果我們能夠可靠地檢測QUIC連接的兩端,就可以查看從客戶端發送至服務器的初始QUIC數據包的可靠性,以及從服務器發送回來的響應QUIC數據包的可靠性。不幸的是,我們不能控制客戶端,所以只能分析第二種可靠性,即從服務器發回客戶端的響應數據包,以及是否有從客戶端收到的后續數據包。
表3展示了這些QUIC響應數據包在24小時內的測量結果。在這里,我們是在服務器上對連接進行觀測的。如果我們看到了初始連接數據包,但沒有后續的數據包,表明QUIC連接失敗。鑒于我們無法觀測到初始QUIC數據包的發送是否存在失敗的情況,因此觀察到的失敗率是一個下限。

表3 QUIC連接失敗率
如前所述,有兩種機制允許服務器向客戶端發出信號,表明它能夠使用QUIC支持HTTP/3會話。簡而言之,這些機制是:
在內容頭中包含一個Alt-Svc指示,即Alt-Svc: h3=":443"。
一個包含有HTTPS RR類型DNS記錄的URL域名,其值為alpn="h3"。
客戶端使用的是哪一種?
測量方法是服務指示只在第二次獲取時使用,而基于DNS的方式可以在第一次使用時建立。在這個實驗中,我們使用了兩個不同的測試。對于執行測量腳本的五分之一(22%)的客戶端來說,其執行了兩次資源獲取,間隔時間為兩秒,其中第二次僅通過在URL獲取的參數中添加一個額外的字段來區分。其余的客戶端則執行一次獲取。這兩次獲取允許服務器通知客戶端,在第一次獲取時通過Alt-Svc頭表明支持HTTP/3,然后在第二次獲取時使用HTTP/3。
表4對比了使用這兩個觸發過程的HTTP/3獲取率。如果客戶端在第一次獲取中不使用HTTP/3,但在第二次獲取中使用HTTP/3,我們認為它使用了Alt-Svc機制。如果客戶端在單個獲取場景中使用HTTP/3,我們假定它使用了DNS HTTPS機制。

表4 QUIC連接觸發率
很明顯,Alt-Svc觸發機制比基于DNS的機制的使用多四倍。造成這種差異的原因是在最近發布的iOS平臺上Safari瀏覽器使用了基于DNS的機制,而Chrome瀏覽器則使用Alt-Svc指示。鑒于約有90%的觀察到的客戶端使用了Chrome瀏覽器,那么在整體客戶端上的觸發率也可以認為是5%。而在整個測量樣本集中看到的1%的基于DNS機制的觸發率源于20%~25%的Safari iOS客戶端。
使用QUIC的動機之一是,建立QUIC會話的開銷低于建立TCP會話和TLS會話的串行延遲。所以詢問觀察到的實踐是否與這一理論相符是很有意義的。
我們將比較客戶端使用HTTP/2加載一個對象(安全會話中的1×1像素gif)的測量時間和同一客戶端使用HTTP/3加載同一對象的測量時間。在客戶端的時間測量中存在許多變量,包括與瀏覽器內部任務調度有關的變量,但這些單獨的因素應該在足夠大的樣本集上被抵消。
圖6顯示了距離中心點+/-500ms的時間差的計數。累積分布顯示,QUIC在2/3的樣本中更快(如圖7所示)。

圖6 資源獲取時間差異的比較:QUIC與非QUIC
很明顯,HTTP/3和QUIC正在今天的互聯網中形成一些明顯的部署趨勢,這主要是由于蘋果的Safari在最近發布的iOS和MacOS中產生的影響。
QUIC對于IP數據包分片進行了保守的規定,最大的數據包尺寸被控制在1200~1360個八位字節范圍內。
盡管蘋果客戶端正在使用DNS HTTPS機制,由于Chrome瀏覽器在互聯網上的廣泛使用,QUIC的主要觸發機制仍然是Alt-Svc指示。
重要的是,HTTP/3和QUIC通常比TCP和TLS快。
我們將繼續開展這一實驗,在未來幾個月內跟蹤QUIC的部署情況。