深入瞭解HTTP/2的前世今生以及Web效能優化總結

amandakelake發表於2018-03-19


HTTP/2的出現,無疑對Web效能的提升帶來了巨大的助力,改變了Web開發者優化網站的方式,但之前一直對它處於模糊的狀態,只知道一些零零碎碎的知識,週末終於靜下心來,從HTTP1開始,找到HTTP/2的存在及其存在必然性,整理了一些內容如下,希望能對有需要的同學產生一點點幫助。


分析之前,先來點直觀好玩的吧

一、讓人興奮的HTTP/2

這個網站做了一個測試:分別利用HTTP/1和HTTP/2協議來下載一張大圖(該大圖由多張小圖組成),HTTP/2完勝 

點進去看看? [HTTP/2 is the future of the Web, and it is here!] 


有個成語叫“事出有因”,每個事物都有其存在的意義(原因),而HTTP/2的誕生自然來自於HTTP/1的一些痛點


二、爺爺HTTP/1的痛點以及解決辦法

HTTP(應用層)建立在TCP(傳輸層)之上,HTTP協議的一些瓶頸以及效能優化都是建立在TCP協議本身的特性之上。 

所以談HTTP之前還是得對TCP有一點點的瞭解(比如對三次握手、四次揮手、慢啟動、往返時延RTT、擁塞視窗cwnd……) 

起碼得知道三次握手和四次揮手是為了防止了伺服器端的一直等待而浪費資源;

知道慢啟動是為了避免擁塞;

知道RTT和cwnd的概念是什麼 

 傳送門:[TCP慢啟動、擁塞避免、快速重傳、快速恢復 - CSDN部落格]


影響網路請求的主要因素有兩個:頻寬和延遲 

頻寬跟網路基礎建設相關暫不談,所以延遲成了web工程師們的頭號公敵。  

http1.0被抱怨最多的兩個問題

> 理解下面兩個問題有一個十分重要的前提:客戶端是依據域名來向伺服器建立連線,一般PC端瀏覽器會針對單個域名的server同時建立6~8個連線,手機端的連線數則一般控制在4~6個。顯然連線數並不是越多越好,資源開銷和整體延遲都會隨之增大。

1、連線無法複用

連線無法複用會導致每次請求都經歷三次握手和慢啟動。三次握手在高延遲的場景下影響較明顯,慢啟動則對檔案類大請求影響較大。 

解決方案:

①HTTP持久連線:Connection:Keep-Alive [HTTP持久連線],痛點在於當前請求必須徹底完成後,下一請求才能正確傳送。 

②http long-polling:長輪詢 

③http streaming:建立起一個tcp連線後,伺服器不會結束streaming請求,持續的通過這個通道返回最新的業務資料,資料通道也是單向的,除非客戶端自動斷開,否則一直保持連線

④websocket:也是基於tcp協議,提供雙向的資料通道,優勢在於提供了message的概念,同時又提供了傳統的http所缺少的長連線功能


2、head of line blocking 線頭阻塞

head of line blocking會導致頻寬無法被充分利用,以及後續健康請求被阻塞,健康的請求會被不健康的請求影響,而且這種體驗的損耗受網路環境影響,出現隨機且難以監控

解決方案: [HTTP管線化]


基於HTTP/1的其他優化手段 

1、Spriting(圖片合併):但有時候只需要其中一張小圖,就會浪費流量 

2、Inlining(內容內嵌):比如把圖片轉化為base64編碼後內嵌到總檔案中,問題同上 

3、Concatenation(檔案合併):粒度變大,一個小的js程式碼改動會導致整個js檔案被下載

4、Domain Sharding(域名分片):瀏覽器或者客戶端是根據domain(域名)來建立連線,多建立幾個sub domain(子域名),那麼同時可以建立的http請求就會更多,連線數變多之後,受限制的請求就不需要等待前面的請求完成才能發出了;只有在請求數非常之多的場景下才有明顯的效果,移動端建議不要使用 [Why Domain Sharding is Bad News for Mobile Performance and Users]



三、爸爸SPDY的改進

HTTP/1存在不少問題,2012年google提出了SPDY的方案,直擊HTTP/1痛點


1、多路複用(multiplexing) 

多路複用通過多個請求stream共享一個tcp連線的方式,解決了http1.x holb(head of line blocking)的問題,降低了延遲同時提高了頻寬的利用率 

2、請求優先順序(request prioritization) 

SPDY允許給每個request設定優先順序,這樣重要的請求就會優先得到響應 

3、header壓縮 

SPDY對header的壓縮率可以達到80%以上 

4、server推送(server push) 

開啟server push之後,server通過X-Associated-Content header(X-開頭的header都屬於非標準的,自定義header)告知客戶端會有新的內容推送過來。在使用者第一次開啟網站首頁的時候,server將資源主動推送過來可以極大的提升使用者體驗。 

5、server暗示(server hint) 

和server push不同的是,server hint並不會主動推送內容,只是告訴有新的內容產生,內容的下載還是需要客戶端主動發起請求。server hint通過X-Subresources header來通知



四、新生代HTTP/2及其特點

HTTP/1.x是一個文字協議,這注定它是非常冗餘的協議,HTTP/2改變了這一點,在HTTP/1.x的語義上,將文字資料封裝在幀裡,並採用二進位制編碼

http2.0的格式定義更接近tcp層的方式,雖然看上去協議的格式和http1.x完全不同了,實際上http2.0並沒有改變http1.x的語義,只是把原來http1.x的header和body部分用frame重新封裝了一層而已。除錯的時候瀏覽器甚至會把http2.0的frame自動還原成http1.x的格式

深入瞭解HTTP/2的前世今生以及Web效能優化總結

理解HTTP/2之前,要先理解兩個概念 幀(frame)和流(stream)[HTTP/2中多路複用:幀(frame)和流(stream)]


HTTP/2和SPDY不同的地方在於,它是業界標準,而SPDY是chrome自家的孩子,馬虎不得,一言一行都得考慮明星效應


所以它有幾個設計前提 

  • 客戶端向server傳送request這種基本模型不會變。 
  • 老的scheme不會變,使用http://和https://的服務和應用不會要做任何更改,不會有http2://。 
  • 使用http1.x的客戶端和伺服器可以無縫的通過代理方式轉接到http2.0上。 
  • 不識別http2.0的代理伺服器可以將請求降級到http1.x。


基於以上原則,HTTP/2繼承了SPDY的部分特性,並基於自己的明星定位做了一些擴充套件,下面介紹HTTP/2的基本概念及其如何優化Web效能的一些實踐。


1、二進位制幀:HTTP/2的“基本單位”

把HTTP/1.x每個請求都當作一個“流”,那麼請求化成多個流,請求響應資料切成多個幀,不同流中的幀交錯地傳送給對方,這就是HTTP/2中的多路複用

深入瞭解HTTP/2的前世今生以及Web效能優化總結

2、多路複用(連線共享)

1、消除了多種通過捆綁相關資產以削減連線數量的長期解決思路的存在必要性

比如(上面的優化手段): 

  • JS和CSS檔案級聯:將多個小型檔案彙總成一個大型檔案,從而降低總體請求數量 
  • 雪碧圖 * Domain Sharding(域名分片):增加整體TCP連線數量 
  • 內容內嵌  

2、請求優先順序和請求依賴 

一個request對應一個stream並分配一個id,這樣一個連線上可以有多個stream,每個stream的frame可以隨機的混雜在一起,接收方可以根據stream id將frame再歸屬到各自不同的request裡面 

所以,HTTP/2裡的每個stream都可以設定優先順序(Priority)和依賴(Dependency),真正解決了關鍵請求被阻塞的問題

3、header壓縮 

SPDY/2使用的是gzip壓縮演算法 

HTTP/2採用的是一種叫HPACK的壓縮演算法

4、Server Push伺服器推送

比如說客戶端請求一個 html, html 裡面含有 css 和圖片,按照正常來講,解析 html 之後要分別發出 CSS 的請求和圖片的請求,但是如果服務端得知頁面支援 server push,客戶端便只需要發出 http 請求,而伺服器直接將 css 和圖片一起發出去,以致請求多個響應未發先至。這就是 server push 的作用,和 inlining 有點類似,但是相比 inlining 有兩個好處,inlining 會影響快取,會增大 html 的體積,包括後臺模板的維護,這也便增加開發和維護成本,對於客戶而言僅僅是多個請求。

5、重置連線

對於HTTP/1來說,是通過設定tcp segment裡的reset flag來通知對端關閉連線的。這種方式會直接斷開連線,下次再發請求就必須重新建立連線。 

HTTP/2引入RST_STREAM型別的frame,可以在不斷開連線的前提下取消某個request的stream,表現更好。


五、HTTP/2下的Web優化觀念

1、核心理念

在HTTP/1下,大家的關注點都在減少向伺服器發起的HTTP請求數,將盡可能多的資源塞進一個連線中,並尋找其他辦法來避免瀏覽器出現線頭阻塞。 

在HTTP/2下,Web開發者應該專注於網站的快取調優,而不是擔心如何減少HTTP請求數。通用的法則是,傳輸輕量、細粒度的資源,以便獨立快取和並行傳輸。 


這種轉變的出現是因為HTTP/2的多路複用和頭部壓縮特性。 多路複用使得不同的請求共用一個TCP連線,允許多個資源並行下載,避免建立多個連線帶來不必要的額外開銷。它消除了HTTP/1.1中的線頭阻塞問題。 

頭部壓縮排一步減少了多個HTTP請求的開銷,因為每個請求開銷都小於未壓縮的等價HTTP/1.1請求。  

HTTP/2還有兩個改變會影響到你的Web優化:流優先順序和服務端推送。前者允許瀏覽器指定接受資源的順序,後者允許服務端主動傳送額外的資源。


2、將會被歷史拋棄的HTTP/1優化手段

如此一來,上面HTTP/1的幾種優化手段就應該被歷史拋棄了:合併檔案(webpack怎麼辦?思考題)、內聯資源、雪碧圖、細分域名


3、依然能複用的優化手段

①DNS預解析:減少DNS查詢時間

DNS查詢需要一個RTT時間,在瀏覽器級別,系統級別都會有層DNS快取,之前解析過的可以直接從本機快取獲取,以減少延遲。 Web標準提供了一種DNS預解析技術,因為伺服器是知道頁面即將會發生哪些請求的,那我們可以在頁面頂部,插入 

<link rel="dns-prefetch" href="//host/">複製程式碼

讓瀏覽器先解析一下這個域名。那麼,後續掃到同域的請求,就可以直接從DNS快取獲取了。 

此外,Web標準也提供prefetch,prerender的預載入技術。prefectch會在瀏覽器空閒的時候,向所提供的連結發起請求,而prerender不僅會請求,還會幫你在後臺渲染頁面。如果在一個頁面中,你知道使用者有很大概率去點某個連結,可以嘗試把這個連結加到prefetch或prerender,那麼使用者就會秒開這個頁面了。 

②使用CDN 

將Web資源通過CDN放在地理上更靠近來訪者的伺服器節點上

③利用瀏覽器快取 

進一步利用內容分發網路,將資源儲存在使用者的本地瀏覽器快取中,除了產生一個304 Not Modified響應之外,這避免了任何形式的資料在網路上傳輸 

④最小化HTTP請求大小和響應大小 

⑤避免不必要的重定向 

重定向意味著要重新發起請求 

這裡要說的一種重定向是,訪問HTTP站點,跳轉到HTTPS,並不是指資源快取的重定向獲取 避免這種跳轉,我們可以用HSTS策略告訴瀏覽器,以後訪問我這個站點,必須用HTTPS協議來訪問,讓瀏覽器幫忙做轉換,而不是請求到了伺服器後,才知道要轉換

在響應頭部加上 Strict-Transport-Security: max-age=31536000即可


六、HTTP/2目前存在的問題以及使用限制

1、HTTP2.0最大的亮點在於多路複用,而多路複用的好處只有在http請求量大的場景下才明顯,所以目前來說,可能更適用於瀏覽器瀏覽大型站點的時候。 

2、HTTP2.0對於ssl的依賴比較強 雖然HTTP2.0也可以不走ssl,有些場景確實可能不適合https,比如對代理伺服器的cache依賴,對於內容安全性不敏感的get請求可以通過代理伺服器快取來優化體驗 

3、移動端iOS9+自動支援HTTP/2,Android理論上來說需要5.0以上才支援(這個理論上非絕對,這裡不說了) 


七、後記

感謝您耐心看到這裡,希望有所收穫! 

如果不是很忙的話,麻煩點個star⭐【Github部落格傳送門】,舉手之勞,卻是對作者莫大的鼓勵。  

我在學習過程中喜歡做記錄,分享的是自己在前端之路上的一些積累和思考,希望能跟大家一起交流與進步,更多文章請看【amandakelake的Github部落格】


參考

HTTP/2.0 相比1.0有哪些重大改進? - 知乎 

從TCP、HTTP/1的問題上分析了為何會誕生HTTP/2 排名第二的那篇文章更加詳細  

[Web 開發者的 HTTP/2 效能優化指南] 

與HTTP/1做了對比,容易理解和記憶 

[Web 的現狀:網頁效能提升指南 - 前端郭高工 - SegmentFault 思否] 

在HTTP/1的基礎上,講的比較詳細有條理 

【網路協議】Web協議未來優化指南

對TCP、HTTP1、HTTPS、SPDY、HTTP2等幾種協議做了對比區分


相關文章