簡介: 衆所周知,QUIC(Quick UDP Internet Connection)是谷歌制定的一種互聯網傳輸層協議,它基於UDP傳輸層協議,同時兼具TCP、TLS、HTTP/2等協議的可靠性與安全性,能夠有效減小鏈接與傳輸延遲,更好地應對當前傳輸層與應用層的挑戰。目前阿里雲CDN線上提供GQUIC版本服務,已經有Tbps級別的流量承載,並對客戶來帶了顯著的延遲收益。本文將由低向上分層討論QUIC協議的特色。chrome
衆所周知,QUIC(Quick UDP Internet Connection)是谷歌制定的一種互聯網傳輸層協議,它基於UDP傳輸層協議,同時兼具TCP、TLS、HTTP/2等協議的可靠性與安全性,能夠有效減小鏈接與傳輸延遲,更好地應對當前傳輸層與應用層的挑戰。目前阿里雲CDN線上提供GQUIC版本服務,已經有Tbps級別的流量承載,並對客戶來帶了顯著的延遲收益。本文將由低向上分層討論QUIC協議的特色。安全
做者:黎叔網絡
本文針對QUIC的系列協議進行科普性簡單介紹,細節讀者仍然須要通讀協議原文。本文基於quic的討論均基於quic-34系列版本。併發
QUIC協議相似快遞公司,在收到用戶數據後,將數據打包,傳輸到對端,再進行拆包,將用戶數據交給了最終目標用戶。QUIC是基於UDP協議,實現了相似TCP的可靠傳輸,並在此基礎上,結合HTTP3/QPACK,更好地服務互聯網上海量的HTTP Request/Response需求。如其名發音,QUIC(quick),其目標就是但願比基於TCP的HTTP交互有更好的體驗。負載均衡
QUIC是在UDP的基礎上,構建相似TCP的可靠傳輸協議。HTTP3則在QUIC基礎上完成HTTP事務。
網絡老是分層討論的,在此咱們由低向上分層討論quic協議tcp
本章節討論QUIC發包的UDP部分的相關問題。性能
荷載大小受限於3個對象:QUIC協議規定;路徑MTU;終端接受能力
一、QUIC不能運行在不支持1200字節的單個UDP傳輸網絡路徑上 QUIC有規定initial包大小不得小於1200,若是數據自己不足1200(好比initial ack),那麼須要用padding方式至少填充到1200字節優化
二、QUIC不但願出現IP層分片現象本要求意味着udp交給ip層的數據不會大於1個MTU,假設mtu爲1500,ipv4場景下,udp的荷載上限爲1472字節(1500-20-8),ipv6下,udp荷載上限爲1452(1500-40-8)。QUIC建議使用PMTUD以及DPLPMTUD進行mtu探測。在實戰中,咱們建議設置IPv6的MTU爲1280,大於這個值,某些網絡會存在丟包現象。ui
三、終端能接受 transport paraments的max_udp_payload_size(0x03)的是終端接受單個udp包大小的能力,發送端應當聽從這一約定。google
UDP荷載內容即爲quic協議中的packet。協議規定,若是不超過荷載大小的限制,那麼多個packet能夠組成一個udp報文發出去。在quic實現中,若是每一個udp報文只包含一個quic packet,會更容易出現亂序問題。
和tcp不一樣,quic須要在應用層就完成udp數據組裝,且每一個udp報文不大於1個mtu,若是不加以優化,好比每一個包直接用sendto/sendmsg發送,勢必會形成大量的系統調用,影響吞吐
一、經過sendmmsg接口進行優化,sendmmsg能夠將用戶態的多個udp quic包經過一次系統調用發到內核態。內核態對於每一個udp quic包獨立做爲udp包發出去
二、在1.)解決了系統調用次數問題,開啓GSO能夠進步一分包延遲到發給網卡驅動前一刻,能夠進一步提升吞吐,下降CPU消耗
三、在2.)的基礎上,如今主流網卡已經支持硬件GSO offload方案,能夠進一步提升吞吐,下降cpu消耗
上面介紹的發送方式,事實上能夠理解爲udp burst發送方式,這帶來了一個問題,擁塞控制須要pacing能力!
在咱們討論時,可知1個udp報文裏傳輸的實際上是一個或多個quic協議定義的packet。那麼在Connection這一層面,實際上是以packet爲單位進行管理的。一個packet到來,終端須要解析出目標ConnectionID(DCID)字段,並將該packet交給找到對應的quic connection。一個packet是由header加payload兩部分組成。
不一樣於tcp的4元組惟一確認一條鏈接的方式,QUIC定義了一個和網絡路由無關的ConnectionID來確認惟一鏈接的。這帶來一個好處,能夠在四元組發生變化時(好比nat rebinding或者終端網絡切換wifi->4G),依然保持鏈接。固然,雖然鏈接狀態依然保持,但因爲路徑發生變化,擁塞控制也須要可以及時調整。
IETF的quic header分爲兩種類型,long header, short header。其中long header有分爲 initial, 0rtt, handshake, retry四種類型。類型的定義能夠直接參考rfc文檔,此處再也不贅述。
quic規定packet number始終爲自增的,就算某個packet的內容爲重傳的frame數據,其packet number也必須自增,這相對於TCP來講,帶來一個優勢,可以更加精確的採集到路徑的RTT屬性。
packet number編解碼: packet number是一個0~262 -1的取值範圍,quic爲了節約空間,在計算packet number時,引入了unacked的概念,經過截斷(只保留有效bit位)的方式,只用了1-4個字節,便可以encode/decode出正確的packet number。rfc文檔中有附錄詳細講解了enc/dec的過程。
packet頭在安全傳輸中是被保護對象,這也意味着在沒有ssl信息的狀況下,沒法使用wireshake對packet進行時序分析。中間網絡設備也沒法向TCP那樣得到packet number進行亂序重組。
在對packet進行解密,且去除掉packet header後,packet的荷載裏就都是frame了(至少包括1個)。
若是packet的荷載裏,不包括ACK, PADDING, and CONNECTION_CLOSE這種三種類型的幀,那麼這個packet則被定義爲ack-eliciting,意味着對端必須對這種packet生成相應的ack通知發送方,以確保數據沒有丟失。
packet的荷載裏frames的類型在多達30種類型,每種類型都有本身的應用場景,如ACK Frame用於可靠傳輸(Recovery),Crypto用於安全傳輸(TLS握手),Stream Frame用於業務數據傳遞,MAX_DATA/DATA_BLOCKED用於流控,PING Frame能夠用於mtu探測,具體描述參考rfc文檔。
QUIC的安全傳輸依賴TLS1.3,而boringssl是衆多quic實現的依賴庫。協議對Packet的頭部以及荷載均進行了保護(包括packet number)。TLS1.3 0RTT的能力,在提供數據保護的同時,能在第一時間(服務端收到第一個請求報文時)就將Response Header發給客戶端。大大下降了HTTP業務中的首包時間。爲了支持0RTT,客戶端須要保存PSK信息,以及部分transport parament信息。
安全傳輸也常常會涉及到性能問題,在目前主流的服務端,AESG因爲cpu提供了硬件加速,因此性能表現最好。CHACHA20則須要更多的CPU資源。在短視頻業務上,出於對首幀的要求,一般直接使用明文傳輸。
Transport Paramenter(TP)協商是在安全傳輸的握手階段完成,除了協議規定的TP外,用戶也能夠擴展私有TP內容,這一特性帶來了很大的便利,好比:客戶端能夠利用tp告知服務端進行明文傳輸。
QUIC協議是須要像TCP可以進行可靠傳輸,因此QUIC單獨有一個rfc描述了丟包檢測和擁塞控制的話題,
丟包檢測:協議利用兩種方式來判斷丟包是否發生:一種是基於ack的檢測,經過time threshold和packet threshold根據已經到達的packet,推斷在此包以前發出去的包是否丟失。第二種,在失去了參考包的狀況下,那麼只能經過PTO的方式來推斷包是否丟失。通常來講,大量被觸發的應該是ACK的檢測方式。若是PTO被大量觸發,會影響發包效率。
擁塞控制:QUIC針對TCP協議中的一些缺陷,專門作了優化。好比始終遞增的packet number,豐富的ack range,host delay計算等。同時tcp的擁塞控制須要內核態實現,而QUIC在用戶態實現,這大大下降了研究高效率的可靠傳輸協議的門檻。Recovery協議中,描述了newReno的實現方式。在GOOGLE chrome中,實現了cubic, bbr, bbrv2,而mvfst項目則更爲豐富,包括了ccp, copa協議。
stream是一個抽象的概念,它表達了一個有序傳輸的字節流,而這些字節其實就是由Stream Frame排在一塊兒構成。在一個quic connection上,能夠同時傳輸多條流。
在Quic協議裏,stream分爲單向流或雙向流,又分爲客戶端發起或服務端發起。stream的不一樣類型定義在HTTP3中獲得了充分的利用。
Stream的荷載即爲一系列Stream Frame,經過Stream Frame頭部的Stream ID來確認單個流。
在TCP裏,若是一個segment傳遞丟失,那麼後續segment亂序到達,也不會被應用層使用,只到丟失的segment重傳成功爲止,所以TCP實現的HTTP2的多路複用能力受到制約。在QUIC協議中,有序的概念僅維護在單個stream中,stream之間和packet都不要求有序,假設某個packet丟失,只會影響包含在這個包裏的stream,其餘stream仍然能夠從後續亂序到達的packet中提取到本身所須要的數據交給應用層。
在引入HTTP3後,stream的單向流類型被擴展成:控制流,Push流和其餘保留類型。其中HTTP3的setting則是在控制流中傳輸,而HTTP數據傳輸是在客戶端發起的雙向流中,因此讀者會發現,HTTP數據傳輸的stream id都是模4等於0的。
在引入QPACK後,單向流被進一步擴展了兩個類型,encoder流,decoder流,QPACK中動態表的更新則依賴這兩個流。
QPACK的做用是頭部壓縮。相似HPACK,QPACK定義了靜態表,動態表用於頭部索引。靜態表是針對常見的頭部,協議預先定義的。動態表則是在該QUIC Connection服務HTTP過程當中,逐漸創建的。QPACK所創建的Encoder/Decoder流是伴隨用於HTTP事務的QUIC Connection生命週期。
動態表不是HTTP3可以運行的必須項,因此在某些QUIC開源項目中,並無實現複雜的動態表功能。
在QPACK的動態表業務中,數據流,編碼流,解碼流3種對象共同參與,編碼流和解碼流負責維護動態表變化,數據流則解析出頭部的索引號,去動態表中查詢,獲得最終的頭部定義。
QUIC協議引入了flow control的概念,用於表達接收端的接受能力。流控分兩級,Connection級別,和Stream級別。發送端發送的數據偏移量不能超過流控的限制,若是達到限制,那麼發送端應該經過 DATA_BLOCKED/STREAM_DATA_BLOCKED來通知接收端。若是爲了傳輸性能,接收端應該儘可能保持限制足夠大,好比達到max_data的一半時,就及時更新max_data傳給發送端。若是接收端不但願太快接受數據,也能夠利用流控對發送端進行約束。
QUIC一開始由google主導設計開發,在chromium項目中,能夠看到google quic(GQUIC)版本號被定義爲Q039,Q043,Q046,Q050等。
隨着IETF版本的QUIC推出,ietf quic(IQUIC)也有不少版本,如29,30,34(最新版)等,不一樣版本多是沒法互通的,好比不一樣版本安全傳輸的salt變量規定不同。因此IQUIC引入了版本協商的功能,用於不一樣的客戶端和服務端協商出能夠互通的版本。
在實踐中,還會遇到一個需求,要求一個服務可以同時服務GQUIC的不一樣版本,又能服務IQUIC的不一樣版本。這就要求服務在收取到packet後,須要對packet做出判斷,分析出它屬於iquic的,仍是gquic的,而後進行邏輯分流。
目前阿里雲CDN線上提供GQUIC版本服務,適用的產品包含靜態內容分發(圖片小文件、大文件下載、視音頻點播)和動態內容分發(全站加速)。用戶只需在CDN、全站加速控制檯對域名開啓【QUIC協議開關】功能,支持QUIC協議的客戶端便可經過QUIC協議與阿里雲CDN節點通訊。
圖片小文件:明顯下降文件下載總耗時,提高效率
視頻點播:提高首屏秒開率,下降卡頓率,提高用戶觀看體驗
動態請求:適用於動態請求,提高訪問速度,如網頁登陸、交易等交互體驗提高
弱網環境:在丟包和網絡延遲嚴重的狀況下仍可提供可用的服務,並優化卡頓率、請求失敗率、秒開率、提升鏈接成功率等傳輸指標
大併發鏈接:鏈接可靠性強,支持頁面資源數較多、併發鏈接數較多狀況下的訪問速率提高
加密鏈接:具有安全、可靠的傳輸性能
關於QUIC協議,目前阿里雲CDN線上的QUIC已經有了Tbps級別的大流量驗證,併爲客戶來帶了顯著的延遲收益。隨着IETF標準的QUIC協議完善,阿里雲也會盡快推出ietf quic服務,咱們相信QUIC將來會成爲互聯網流量的主力成員。
後續阿里雲CDN會在「阿里雲Edge Plus」公衆號中分享更多最新的產品能力、解決方案和技術實踐,歡迎你們關注,與咱們一塊兒探討。
原文連接本文爲阿里雲原創內容,未經容許不得轉載。