HTTP/2 又可以簡稱 h2 ,是基於 HTTP/1.1 修改的第二版 HTTP 協議,介紹的部分可以參考 WIKI ,今天想討論的是使用 h2 的缺點。在討論缺點之前,必須先了解 HTTP/2 跟 HTTP/1.1 比起來改進了什麼,以及如何做到的,才能進一步討論 h2 的好壞處。

HTTP/1.1 的問題

h2 最大的目標就是改善了傳輸的延遲(Latency),基本的想法是這樣:我們知道 HTTP/1 的問題是每一個 request 都必須要開啟新的 tcp connection,而 tcp connection 是一個非常耗時的動作,建立連線需要走三向交握,來回確認後才能連線,以及保證送達的特性,所以如果每一個 request 都要重新建立一個新的 connection ,HTTP 的傳輸就會變得很冗長,網頁載入的速度大幅受到影響,特別是在現在網頁的為了內容的美觀、合理性(UI/UX)等,使用大量的 js, css, img ,因此 HTTP/1.1 立刻改善了這個問題 (keep-alive),允許一個 connection 重複使用,來傳輸所需要的資源。

但這還是有一個問題,因為 HTTP/1.1 的傳輸是有序的,一個 request 過去之後,必須等待 response 回來才能夠傳送下一個 request,因此這個隊列中如果有一個 request or response 很肥大,他就會卡住其他的等待中的 req & res,這個問題就是 head of line blocking (HOL Blocking)。

所以隨著技術不斷的發展,有很多新的技術要解決/改善這個問題(http pipelining, connection parallel in browser, Webpack… etc)而 h2 也是其中之一,而且是最有效的。

h2 使用了 binary framing 的技術,把資料變成更小的 binary data ,在新的資料格式下,requests 可以不必要等待上一個 request 的 response 回來才能夠發送,讓 requests 是同時並行發送的,而 response 也是一樣,可以不用依照 request 的順序回來,有效地解決了 HOL Blocking 的問題。

跟 http pipelining 不同的是 http pipelining 雖然可以同時同時發送 requests ,但是 responses 的回應依然是有序的,所以在解決 HOL Blocking 上的效果並不大(應該可以想像卡住其實大多是因為肥大的 response resource 造成的),這也是為什麼很多人覺得 http pipelining 是沒用緣故。

簡單整理一下:

  • HTTP/1.1: request 是有序列的,而且在上一個 request 的 response 返回之前,沒辦法發送下一個 request ,這個問題就是 HOL Blocking。
  • HTTP/1.1 with multiple connections: 基於上述的 http/1.1 browser 建立多個 tcp connection 來分散等待的時間,是一種蠻有效的方式,但最大的問題是比起其他的 solution ,這個解決方案的成本是更高的。
  • HTTP Pipelining: 允許 requests 可以同時發送不需要等待上一個 request 的 response ,但是 response 回來的依然是有順序的。
  • HTTP/2: 允許 requests 可以同時發送不需要等待上一個 request 的 response,而 response 也是一樣,不需要依照順序返回。

雖然 h2 能有效解決 HOL Blocking 的問題,不過並沒有辦法改變肥大的檔案傳輸的速度比較慢的事實,根據統計,大部分的網站使用 h2 之後載入的效益大約提升 11.8% ~ 47.7 % 之間,落差還蠻懸殊的。

h2’s pros & cons

如果 h2 這麼好,那現在大家應該都要全面改用 h2 才對,事實上 h2 也有缺點存在,上面有提到,h2 有效地解決了 request & response 之間堵塞的問題(也還有一些其他的改進,這邊先略過),但是如果網頁堵塞的情況不嚴重,其實 h2 跟 http/1.1 的差異就不大,都是文字資料的傳輸,基本上就不太會有 HOL Blcking 的問題 (或是影響沒這麼大)。不過使用了 h2,web server 本身必須付出額外的成本,server 要計算 binary frame ,並把它轉換成 request or response ,對於 CPU 來說,就多了額外的工作來做 encoding, decoding 的動作(對於 memory 來說成本並不會增加,因為都是要處理一樣的資料),CPU 額外的負擔有可能影響沒這麼多,但是到大流量的情況下,這可能會是一個要討論的地方。

另外 h2 並沒有解決 tcp-level blocking,tcp 的傳輸單位是 packet ,他是有序的,而且必須保證一定送達 ,所以只要 packet 有延遲、堵塞,基本上 h2 也是沒輒,必須等待封包的傳輸完成,才能夠解析成 reuest or response。HTTP/3 (QUIC) 有打算解決這個問題,它的技術核心改用了 UDP ,避免了 TCP 的限制,針對上述的情況應能提供很有效的解決方案,但現在還沒完成,仍是草案階段。

ps. 其實我一直覺得 HTTP 這一種 stateless 的協議使用 TCP 感覺很浪費,TCP 的成本高,設計上是用來保持長時間連線用的才對

Reference