HTTP/2探索第一篇——概念

版權聲明:本文由張浩然原創文章,轉載請註明出處: 
文章原文連接:https://www.qcloud.com/community/article/87算法

來源:騰雲閣 https://www.qcloud.com/community瀏覽器

 

一.現狀

如今網絡優化的瓶頸是什麼?你可能會說,帶寬。也許在2014年前,決定性能的關鍵是帶寬,可是在今天以及之後,瓶頸都不會是帶寬,而是延遲;

從圖中能夠看出,隨着帶寬的增加,頁面加載時間(PLT Page Load Time)在1Mbps到3Mbps的區間獲得了很大的改善,可是再提升帶寬,帶來的提高就很小了,屬於非線性改善;反觀延遲,延遲(這裏是指多個RTT時間相加的總和)的改善對於頁面加載時間是屬於線性改善;緩存

1. HTTP/1.1

TCP鏈接是須要三次握手的,同時,多個TCP鏈接也會給服務器帶來資源的消耗,在HTTP/1.1中,每一個請求回覆都是一次TCP鏈接(未開啓Keep-Alive的狀況下),而且,同時傳輸多個資源時,會有隊首阻塞的問題,形成網絡資源沒法有效利用;安全

2. 安全

對於大多數人來講,下圖的狀況幾乎都有遇到過(電腦或手機裏)。萬惡的運營商或者網絡接入WiFi提供商劫持咱們的網絡,修改網絡的內容,給咱們帶來了很大的困擾;
服務器

二.HTTP/2.0

如今,HTTP/2.0出現了。其實HTTP/2.0是支持Clear Text版和Over TLS版,因爲現有支持HTTP/2.0的瀏覽器都是實現的Over TLS版,故本文的HTTP/2.0都是講的是HTTPS版HTTP/2.0;網絡

1. Clear Text版:

  • 客戶端向服務端請求(假設此時scheme是HTTP),帶有如下頭:
    Upgrade: h2c
    HTTP2-Settings性能

  • 服務器端返回:
    101狀態碼,轉換協議;
    Connection: Upgrade
    Upgrade: h2c 或者 200/404優化

2. HTTP/2.0 Over TLS版:

  • 客戶端向服務器端請求
    TLS + ALPN(Application Layer Protocol Negotiation)/NPN網站

  • 服務器端返回:
    TLS 握手 並返回支持的HTTP協議;
    a. TLS握手詳細過程

    b. ALPN協商過程
    參考TLS握手過程圖,下面是增長ALPN協商的具體過程:
    客戶端添加一個ProtocolNameList字段,包含支持的HTTP協議到ClientHello消息中;
    服務器端查看ProtocolNameList字段後經過ServerHello消息返回ProtocolName字段,代表被選定的協議;
    經過實現ALPN,再也不須要單獨請求一次服務器帶上Upgrade: h2c;
    c. False Start
    一般狀況下,使用ALPN會搭配使用False Start,客戶端在完成TLS握手前提早發送加密後的應用數據,將兩次RTT TLS握手減小爲一次;不過須要同時支持ALPN(NPN已經不多用啦)和前向安全性;
    d. HSTS
    HTTP Strict Transport Security(簡稱爲HSTS)是一個安全功能,告訴瀏覽器只能經過HTTPS訪問當前資源,禁止HTTP方式。
    若是用戶輸入域名www.qq.com, 瀏覽器首先會去請求http://www.qq.com ,請求過程是明文非加密的,此時容易被中間人攻擊,讓網路惡意中間商直接接觸到用戶信息;而HSTS是用戶請求時,服務器告訴客戶端,下次來請求直接請求https:// ,而不要再請求服務器來跳轉到https;
    同時,開啓HSTS後,若是證書認證不經過(好比遭到中間人攻擊),瀏覽器此時強制沒法打開該網站;編碼

3. 名詞解釋

流(Stream):一個Stream是包含一條或多條信息,ID和優先級的雙向通道;
消息(Message):消息由幀組成;
幀(Frame):幀有不一樣的類型,而且是混合的。他們經過stream id被從新組裝進消息中;

4. 概念解釋

a. 二進制幀

HTTP2的二進制幀是9字節(72 bit)
長度:24bit,也就是理論上能夠攜帶2^24字節的數據。但一般因爲SETTINGS_MAX_FRAME_SIZE的設置,不能發送超過2^14(16384)字節的數據;
類型:8bit,決定了該幀的類型;

  • DATA : 數據幀
  • HEADERS : 頭部幀
  • PRIORITY : 設置流的優先級
  • RST_STREAM : 終止流
  • SETTINGS : 設置鏈接參數
  • PUSH_PROMISE : 服務器推送模擬請求幀
  • PING : 用來計算RTT時間和看是否服務器掛了的Stream
  • GOAWAY : 告訴對方中止再向當前鏈接建立stream
  • WINDOW_UPDATE : 流量控制
    保留字段:1bit,通常爲0;
    Stream ID:31bit,Stream標識,理論上能夠有2147483648,超過這麼多stream怎麼辦呢?
    若是是客戶端沒法再建立新的stream id,能夠直接建立新的TCP鏈接,stream id被重置;
    若是是服務器端沒法再建立新的stream id,服務器將會給客戶端發一個 GOAWAY幀,客戶端沒法再向該服務器建立stream,不得不新建TCP鏈接;

5. 新特性

a. 多路複用

HTTP/2.0中,數據在發送端被切分爲更小的數據幀用以高效利用連接;
HTTP 1.1時代,再不開啓Keep-alive的狀況下,每個請求會佔用一個TCP鏈接,而HTTP/2將請求和響應消息拆分爲各自獨立的幀,交錯的發送,而後再在接收端從新裝配組合。有什麼好處呢?
交錯的多個請求/響應之間互現不會被阻塞

  • HTTP/1.1時代的Keep-alive也是保持同一個TCP鏈接,可是因爲請求/接收有前後,後面的請求資源會被前面的資源阻塞(沒收到響應時不會發新的請求),以下圖最左和最右邊所示,即使是相比HTTP管道,優化也是巨大的:

    減小了沒必要要的延時,改善了網路的利用率(多路複用和資源優先級/依賴關係搭配使用,使得頁面重度依賴的資源優先傳輸);

b. 頭部壓縮
HTTP/2.0使用HPACK來給頭部壓縮;

  • 值經過霍夫曼編碼;
  • 以前發送的值都被索引發來,以後使用時發現以前發送過該Header字段,而且值相同,就會沿用以前的索引來指代那個Header值;
  • Cookies:在HTTP/2.0中,Cookie也將會變爲鍵值對索引發來,而不是一長串字符串;

能夠看看咱們組dream同窗的HTTP/2.0之特性科普篇——頭部壓縮,裏面有截圖部分的數據講述壓縮後的效果;

這裏須要講解一下僞頭部字段:

請求:

  • authority
  • method
  • path
  • scheme

響應:

  • status

全部的僞頭部字段都是在全部Header的前部;

c. 資源優先級/依賴關係
資源優先級/依賴關係經過stream權重dependency來設置;

經過上圖能夠看到,有一列是叫做Priority,初始設置是根據Content-type來設置優先級的,好比HTML是Highest,CSS是High,而後JS是Medium;
Stream 權重值能夠設置爲1到256之間;
Stream能夠明確的表示依賴關係;
注意,必定要理解權重和依賴,權重值和依賴關係是做爲帶寬資源/服務器/客戶端處理資源的建議值,但並不能保證他們有特定的傳輸順序。讓咱們來看一張HTTP/2.0 的依賴關係和權重圖:

HTTP/2.0中的stream都默認是依賴於一個根stream(其實不存在)。權重值是針對同級來計算的,不一樣級是不用來計算的;

d. 流量控制
與TCP的流量控制相似,不過HTTP/2.0的流量控制能夠到具體幀,而TCP是TCP鏈接層面上的。注意:流量控制目前只對DATA幀有效!流量控制的算法沒有具體要求使用哪種,可是大概實現的功能是這樣的:

  • 兩端收發保有一個流量控制(window)窗口;
  • 發送端每發送一個DATA幀,就把窗口的大小遞減,遞減量爲這個幀的大小,要是窗口大小小於該幀的大小,那麼這個幀就必須被拆分。若是窗口值等於0,就不能發送任何幀。流量控制的初始默認窗口值大小爲65535字節(理論上能夠設置2^31-1字節也就是2147483647字節大小的窗口值)。
  • 接收端能夠經過發送WINDOW_UPDATE幀給發送端,發送端以幀內指定的窗口大小增量加到窗口大小限制上。

e. Server Push
Server Push的資源一樣須要遵照同源策略,經過:authority來判斷;

如Demo裏所示,若是在服務器端設置當請求Path/examples/dashboard時就推送/examples/dashboard/d3.js,如今咱們來看抓包:

說明:
當客戶端請求服務器時(此時的請求路徑已經設置好推送),服務器發回一個PUSH_PROMISE和兩個HEADERS Frame,從Stream Identifier能夠看出,第一個HEADERS的Stream ID是1,也就是複用請求的Stream來返回(這是HTML文件的返回響應Header)。第二個HEADERS就是推送文件的響應Header。
根據定義,由客戶端初始化發起的Stream的標識符是奇數,由服務器端初始化發起的Stream是偶數,圖中能夠體現;
那麼Stream 1和Stream 2的順序如何保證呢?說明文檔裏有這樣一句話:

Pushed streams initially depend on their associated stream.

也就是說,服務器將要推送的資源依賴於觸發推送的請求,根據Stream依賴的功能,只有被依賴的stream加載完後纔會去加載接下來的stream;

Server Push有什麼好處呢:
推送的資源能夠被客戶端緩存;
推送的資源能夠被不一樣的頁面複用;
推送資源也是支持多路複用的;
推送資源能夠被客戶端拒絕掉(客戶端接收到PUSH_PROMISE後,能夠選擇發送RST_PROMISE來拒絕接收,告訴服務器端不要再發送了,固然,此時可能已經有部份內容已經發送過來了);
同時,Server Push配合流量控制,能夠實現不少很神奇的功能,這裏賣個關子,而後會在下一篇講解 :)

參考
HTTP/2之特性科普篇
《High Performance Browser Networking》——Ilya Grigorik;
《Web性能權威指南》-李鬆峯翻譯;
Jerry Qu blog 中的HTTP/2專題;
HTTP/2.0 RFC7540
HTTP/2.0協議 中英對照——百度FEX

文章來源於公衆號:小時光茶社(Tech Teahouse)

相關文章
相關標籤/搜索