Google Quic協議


 

0x01 Quic

QUIC協議於2012年實現,2015年提交RFC草案,它是Goolge為了解決當今WEB應用常見的傳輸層和應用層問題而提出的,從分層結構上可以看做是TCP+TLS+HTTP2的集合,不過是在UDP的基礎上實現的

主要解決了下面的幾個問題

  1.  Connection establishment latency(連接時延)
  2.  Flexible congestion control (擁塞控制)
  3.  Multiplexing without head-of-line blocking (HOLB問題)
  4.  Authenticated and Encrypted Header and Payload (頭部加密)
  5.  Forward error correction (前向糾錯)
  6.  Connection migration(連接遷移)

0x02 HOLB問題

HOLB(Head of Line Blocking),當所有請求必須按序執行時,會造成后續請求即使已經達到處理的條件也會由於前面的請求阻塞而阻塞的現象。網絡中大量存在着按序的原則,例如路由器轉發隊列需要按序轉發、TCP報文需要按序到達等,HTTP請求在多個層次上也都存在該問題,

HTTP事務級別的 HOLB

在HTTP1.0時代,HTTP請求只能遵循請求-應答、請求-應答的模式,效率極低,一般瀏覽器都開啟多條流來並行多個請求(Chrome 6條)。HTTP1.1引入了Pipelining機制,實現流水線請求,客戶端可以一次性向服務端發送多個請求,但HTTP 1.X要求多個HTTP響應必須按序到達,例如請求r1和r2的響應各有幾個報文,[r1p1, r1p2]和[r2p1, r2p2],HTTP1.X要求報文按序到達,后面的請求被前面的請求阻塞在服務器,造成了HTTP層面的HOLB問題,大多數瀏覽器因此並沒有采用Pipelining而是沿用之前的多流機制。SPDY打破了HTTP1.X的交付順序,允許響應報文亂序到達,例如按照[r2p1, r1p1, r1p2, r2p2]的順序到達,從而解決了HTTP事務層面的HOLB問題。

HTTP HOLB

 

TCP級別的 HOLB

SPDY解決了HTTP事務層的HOL問題,但無法解決TCP層的HOL問題。TCP的可靠性要求所有數據按序交付應用層,發生丟包時接收端會收到大量亂序(Out of Order)的報文,這些報文只能暫時緩存在TCP接收緩沖區中,並不能交付應用層,造成后面請求響應報文由於前面請求響應報文的丟包而不能被應用層讀取。UDP就不存在這個問題,應用層可以提前讀取亂序但有價值的數據,在采取多路復用時,不會因為某個響應丟包而造成所有響應都被阻塞在內核緩沖區中,因此Quic采用UDP作為傳輸層協議。

 

0x03 連接建立時間

基於傳統TCP的WEB應用每次請求至少經過1-3個RTT才能建立連接,包括TCP三次握手和TLS交換秘鑰的時間,在長連接中,這點時間不算什么,但在短流時,連接建立時間可能在響應時間內占有相當大的比重,Google也做了相當多的工作來優化連接建立時間。

 

早些年,Google還搞過TFO(TCP Fast Open )用來加速連接的建立,傳統TCP其實可以在SYN報文內攜帶數據的,只不過應用層無法在三次握手前讀取[rfc793],主要在可靠性與安全方面的考慮,在三次握手前就交付數據可能會帶來幾個問題,一個就是SYN-Flood攻擊可以直接向服務器傳輸數據。TFO通過Cookie的方式防御這種攻擊,服務器在初始連接中向客戶端發送一個Cookie,之后客戶端通過該Cookie向服務器證明自己,服務端在SYN-ACK報文內就可以發送數據了,減少了整整一個RTT的時間。

 TFO初始連接TFO通過Cookie連接

 QUIC同樣采用了Cookie的機制來驗證客戶端的合法性,從而將整個連接建立過程減少到至多1個RTT,除了在初始連接中服務器需要發送證書和Cookie之外,客戶端都可以直接用Cookie在建立連接的同時發送數據。

 

 

 

0x04 其它特性

擁塞控制算法

TCP的擁塞控制算法一直被詬病,以至於UDT、KCP等都是基於UDP實現自己的可靠性與擁塞控制。Quic目前擁塞控制算法目前采用Cubic。Quic的ACK報文中攜帶這接收端在接收報文與發送ACK報文之間的時間間隔,發送端根據該間隔可以更精確地測量鏈路時延,TCP-Vegas等基於時延的擁塞控制算法在將來都有在其基礎上實現的可能。

前向糾錯(Forward Error Correction

FEC機制下每隔幾個報文就發送一個FEC報文,FEC報文為一組報文的異或,在發生丟包時,可以通過未丟失的報文和FEC報文將丟包恢復出來,減少了不必要的重傳。QUIC若干個報文組成一個FEC組,這樣增加了每個報文的負載,但減少了重傳,是一種空間換時間的做法,報文冗余度是一個可控的參數,冗余度越大消耗的帶寬越大,同時減少了重傳數。QUIC類似於RAID4

連接遷移(Connection Migration

一條TCP流由原宿IP、原宿端口和協議來標識,而一條Quic流由一個變長ID(0,8,32,64位)唯一標識,這樣Quic流並不依賴於IP地址。一方面,當某個網卡崩潰后,QUIC並不需要重新建立連接,只需要切換到另外一個網卡,提高了可靠性;另一方面,QUIC天然具備了Multipath的特質,讓多個網卡同時工作,通過添加調度器和多流擁塞控制算法,QUIC可以實現MPTCP的功能,而且是在一個更高的層次上。

0x05 搭建Quic服務器

google自己的chromium項目里已經支持了QUIC,不過不夠方便,go語言編寫的WEB服務器Caddy已經能夠較好地支持Quic與HTTP2.0了,已經在個人服務器上搭建了Caddy-Server,地址為 https://m.codingmozart.com/ ,當然在Google的各大網站不斷F5也是可以看到QUIC的。

Chrome瀏覽器已經支持QUIC,通過chrome://flags/#enable-quic開啟QUIC功能,並在chrome://net-internals/#quic里可以看到所有活躍的QUIC流。

Wireshark可以抓到QUIC的包,在報頭部分可以看到連接號CID(Connection ID)和報文號Sequence類似於TCP的Seq,報文的主要內容被編碼在了負載部分

QUIC有三種類型的報文

Frame Packet:攜帶一個個數據幀,數據幀類型包括ACK,STREAM,WINDOW_UPDATE等等,其中STRAM類型的Frame就是用來實現Multiplexing的,一個幀可以攜帶多條流的分片。

 +--------+---...---+--------+---...---+
 | Type   | Payload | Type   | Payload |
 +--------+---...---+--------+---...---+

FEC Packet:攜帶一組報文的異或,用來前向糾錯

 +-----...----+
 | Redundancy |
 +-----...----+

Public Reset Packet

      0        1        2        3        4         8
   +--------+--------+--------+--------+--------+--   --+
   | Public |    Connection ID (64)                ...  | ->
   |Flags(8)|                                           |
   +--------+--------+--------+--------+--------+--   --+

        9       10       11        12       13      14
   +--------+--------+--------+--------+--------+--------+---
   |      Quic Tag (32)                |  Tag value map      ... ->
   |         (PRST)                    |  (variable length)
   +--------+--------+--------+--------+--------+--------+---

0x06 參考文獻

[1] https://tools.ietf.org/html/draft-tsvwg-quic-protocol-00#ref-QUIC-CRYPTO


免責聲明!

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



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