版權聲明:本文由張浩然原創文章,轉載請註明出處:
文章原文連接:https://www.qcloud.com/community/article/87算法
來源:騰雲閣 https://www.qcloud.com/community瀏覽器
如今網絡優化的瓶頸是什麼?你可能會說,帶寬。也許在2014年前,決定性能的關鍵是帶寬,可是在今天以及之後,瓶頸都不會是帶寬,而是延遲;
從圖中能夠看出,隨着帶寬的增加,頁面加載時間(PLT Page Load Time)在1Mbps到3Mbps的區間獲得了很大的改善,可是再提升帶寬,帶來的提高就很小了,屬於非線性改善;反觀延遲,延遲(這裏是指多個RTT時間相加的總和)的改善對於頁面加載時間是屬於線性改善;緩存
TCP鏈接是須要三次握手的,同時,多個TCP鏈接也會給服務器帶來資源的消耗,在HTTP/1.1中,每一個請求回覆都是一次TCP鏈接(未開啓Keep-Alive的狀況下),而且,同時傳輸多個資源時,會有隊首阻塞的問題,形成網絡資源沒法有效利用;安全
對於大多數人來講,下圖的狀況幾乎都有遇到過(電腦或手機裏)。萬惡的運營商或者網絡接入WiFi提供商劫持咱們的網絡,修改網絡的內容,給咱們帶來了很大的困擾;
服務器
如今,HTTP/2.0出現了。其實HTTP/2.0是支持Clear Text
版和Over TLS
版,因爲現有支持HTTP/2.0的瀏覽器都是實現的Over TLS版,故本文的HTTP/2.0都是講的是HTTPS版HTTP/2.0;網絡
客戶端向服務端請求(假設此時scheme是HTTP),帶有如下頭:
Upgrade: h2c
HTTP2-Settings性能
服務器端返回:
101狀態碼,轉換協議;
Connection: Upgrade
Upgrade: h2c 或者 200/404優化
客戶端向服務器端請求
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後,若是證書認證不經過(好比遭到中間人攻擊),瀏覽器此時強制沒法打開該網站;編碼
流(Stream):一個Stream是包含一條或多條信息,ID和優先級的雙向通道;
消息(Message):消息由幀組成;
幀(Frame):幀有不一樣的類型,而且是混合的。他們經過stream id被從新組裝進消息中;
a. 二進制幀
HTTP2的二進制幀是9字節(72 bit)
長度:24bit,也就是理論上能夠攜帶2^24字節的數據。但一般因爲SETTINGS_MAX_FRAME_SIZE的設置,不能發送超過2^14(16384)字節的數據;
類型:8bit,決定了該幀的類型;
a. 多路複用
HTTP/2.0中,數據在發送端被切分爲更小的數據幀用以高效利用連接;
HTTP 1.1時代,再不開啓Keep-alive的狀況下,每個請求會佔用一個TCP鏈接,而HTTP/2將請求和響應消息拆分爲各自獨立的幀,交錯的發送,而後再在接收端從新裝配組合。有什麼好處呢?
交錯的多個請求/響應之間互現不會被阻塞
b. 頭部壓縮
HTTP/2.0使用HPACK
來給頭部壓縮;
能夠看看咱們組dream同窗的HTTP/2.0之特性科普篇——頭部壓縮,裏面有截圖部分的數據講述壓縮後的效果;
這裏須要講解一下僞頭部字段:
請求:
響應:
全部的僞頭部字段都是在全部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幀有效!流量控制的算法沒有具體要求使用哪種,可是大概實現的功能是這樣的:
e. Server Push
Server Push的資源一樣須要遵照同源策略,經過:authority來
判斷;
如Demo裏所示,若是在服務器端設置當請求Path/examples/dashboard時就推送/examples/dashboard/d3.js
,如今咱們來看抓包:
說明:
當客戶端請求服務器時(此時的請求路徑已經設置好推送),服務器發回一個PUSH_PROMIS
E和兩個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)