Hello quic

背景
http1.x的不足,從1999年誕生的http1.1,通過近20年的發展,已經有許多豐富的功能,至今也是web世界的主要應用層協議,在電商,內容互聯網,雲存儲網絡上都有大範圍的應用,1.1以前的版本很少說了,主要描述下1.1的在現代網絡中的不足,這也是開啓http3.0時代的一個重要因素。
http1.1一個典型的請求格式是:
User-Agent: PostmanRuntime/7.15.0
Accept: */*
accept-encoding: gzip, deflate
Connection: keep-alive
響應格式:
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/html;charset=UTF-8
Content-Length: 606
或者是chunk的模式
可是,看一個了例子:
這些指標的說明: developers.google.com/web/tools/c…
這個是http1.1的golang延遲測試,停滯時間比較長,主要緣由仍是http的請求是串行的。那後邊有個http2的改進,看下效果: http2.golang.org/gophertiles…
主要優化點仍是在http2的編碼格式,頭部壓縮,cookie的映射,多路複用提高的,主要仍是最後一條,可是依然有一個問題,若是是在網絡條件ok的狀況下是沒有明顯問題的,使用http2也能由於多路複用達到縮短用戶請求時間的需求,可是若是是網絡環境較差的狀況下呢,看個例子:
http2依然也是有嚴重的排隊問題,這裏的網絡設置是4G網絡,網絡可靠性設置的是90%,模擬網絡不穩定
http1:從時長上看,雖然HTTP1的時長不必定就比http2的長了,圖片也加載完了,也沒有出現斷網的狀況,也就是說網絡相對http2來講沒那麼擁塞。
  • 究其緣由,網上也有不少的解釋,我的理解主要仍是這裏的多路複用是用應用層的實現,在傳輸層並無解決tcp的隊頭阻塞隱患,由於tcp的可靠性是經過有順序的序號且按照序號順序處理的,並且擁塞控制可能也不是完美的適合弱網,具體的這裏的詳細分析能夠參考: mp.weixin.qq.com/s?__biz=MzU…
  • 總結下http基於tcp的一些問題:
  1. TCP鏈接耗時,三次握手,優化的TFO(具體參考: tools.ietf.org/html/rfc741…) 更新也是比較困難的。
  1. TLS1.2鏈接耗時,至少須要一個RTT
  1. TCP的header沒有被校驗
  1. http2的多路複用在某種狀況下回加重head of line的問題
  1. 重複包確認致使的RTT誤判


  • 因此google率先作了一些嘗試並取得了必定的成功,2009年SPDY開始開發和設計,在2012年IETF小組也參考了SPDY設計了本身的QUIC協議,並但願得到推廣,2016年Google也中止對SDPY的更新,quic的出現一個重要的能力就是能在上邊那個弱網狀況下作的更好。下邊說的quic都是IETF的quic,若是瞭解http2會發現不少設計例如frame,stream和http2很類似。
quic協議特性分析
協議定義細節
header
header可進行壓縮處理,使用QPACK做爲壓縮算法,搭載的流類型是HEADER STREM,其格式是普通的key-value,沒有像http規定的那種固定格式,可搭載的key是HEADER FRAME中容許出現的。
stream
這個概念能夠理解爲一個http的請求、響應,多個stream能夠併發的在一個connection上執行,它們之間沒有順序關係,stream這個概念在傳輸層上,應用層不關心,stream按照搭載的數據用途不一樣分爲多種類型,有control stream,push stream,request stream。這裏說明下,push stream就是服務端->客戶端的流,不管是被動響應仍是主動推送的。stream內部就是多個frame組成的本次請求,不過這裏的frame不是http層面的frame,它是傳輸層本身用來管理一個stream上的數據用的,作buffer, 排序,輸出一個可靠傳輸的數據流。
frame
frame是一個http layer的幀,全部的frame都是搭載在stream上的,不一樣類型的frame可能容許出現的stream不同:

全部的frame都是以下格式:
type是表明這個frame的類型,值是一個有符號整數,length表明的是frame payload的數據長度,值也是一個有符號整數,frame payload就是按照type描述的frame進行存儲數據的,例如是一個headers的frame的話就要按照header的格式定義存放,必須是可識別的格式,不然認爲是HTTP_MALFORMED_FRAME錯誤,或者在沒有讀取到結束符就無數據了也認爲是出現該種錯誤的。
具體的重要的frame有:
DATA: 搭載二進制數據的幀類型,必須是HTTP request/response的數據若是出如今其它stream(control stream),就認爲是HTTP_MALFORMED_FRAME。
HEADERS:做爲quic的header block,只容許出如今requst/push stream上。
剩下的可看下draft-ietf-quic-http的RFC
http message處理
request的message能夠在不發送徹底後服務端就發送完整的response message,一個stream上只能搭載一個request message,而response message能夠在一個stream上有多個。

協議歸協議,在實現的時候仍是要考慮現實問題,例如爲了解決隊頭阻塞問題,雖然用了udp,可是TLS也有record的阻塞,因此,儘可能一個frame不大於MTU,這樣每一個frame都是獨立校驗的,不會阻塞,
功能特性
減小TCP三次握手及TLS握手時間
1.傳輸層0-RTT創建鏈接
2.加密層0-RTT創建加密鏈接
擁塞控制靈活
雖然一些算法都是copy的tcp的可是與tcp不一樣的是它的控制位置,tcp在網絡協議棧上,擁塞控制對網絡的穩定性(網絡切換)和可靠性(丟包)比較敏感。同時在kernal中更新升級應用程序每每是痛苦且漫長的。
quic的改進的地方主要仍是增長了擁塞控制算法的種類,且熱更新,應用能夠根據自身狀況進行動態調整,同時tcp包丟失後的重傳致使packet numer重複的問題可獲得了重視:
  • quic包重傳示意圖
  • stream視角的包重傳示意圖
同時,ack的時間計算更加精確,考慮了server端的處理時延。
在流量控制上,從兩個方面觸發,一個是stream的流量控制上,一個是從connection的流量控制上出發:
  • quic 流量控制示意圖
解決head of line問題
  • tcp 可靠傳輸示意圖


  • tcp TLS包丟失示意圖

  • quic可靠傳輸示意圖
如上圖,若是有stream的包丟失了,那不影響其餘stream的傳輸,並且,傳輸的基本單元packet,通常超過MTU,這樣,加密的時候基於packet進行,儘可能避免了TLS的阻塞問題。
鏈接可遷移
quic的鏈接不是面向鏈接的鏈接,而是一個id標識,這樣若是用戶進行了網絡切換了也能在這個鏈接上繼續傳輸。而這樣作相比直接用新的quic鏈接的優點是省去了TLS的握手。由於基於該鏈接的話是有CACHE的,在服務端上這個鏈接是可用的,沒有發送Close的frame,根據協議說明,目前只支持failover的狀況。
基於quic和http的性能對比
在網絡wifi信號好的狀況下:



在網絡丟包,穩定性不佳的狀況下:
由於charles好像不能代理quic,因此我這裏使用的是mac的網絡模擬工具:
quic的表現:

http2的表現:
參考
HTTP3的演化歷程: www.infoq.cn/article/IgM…
quic協議原理分析: zhuanlan.zhihu.com/p/32553477
相關文章
相關標籤/搜索