從HPACK到多路復用,揭秘HTTP/2如何終結網絡擁堵
頭部壓縮 (HPACK)
在HTTP/1中,每個請求和響應都會發送大量重復的頭部信息,比如 Cookie、User Agent、Accept 等,會使得大量帶寬被這些冗余的數據占用。為了解決這個問題,HTTP/2引入了HPACK算法來壓縮頭部信息。HPACK算法有兩個主要的特性。
1)靜態表(Static Table)和動態表():用來存儲頭部字段。靜態表包含了61 種常見的頭部字段,如":method"、":path"等。動態表則是在會話過程中動態更新,它存儲了最近使用的頭部字段。同時HPACK會建立一種稱為“索引”的機制,用于快速查找和引用兩個表中的鍵值對。這樣對于相同的鍵值對數據,只需發送對應的鍵值就行。
1)靜態表 (Static Table): 預定義了61個常用的HTTP頭部字段名及其常見值(如 :method: GET, accept-encoding: gzip, deflate)。這些條目有固定的索引。
2)動態表 (Dynamic Table): 在連接的生命周期內,由編碼器和解碼器共同維護。新遇到的或不適合靜態表的頭部鍵值對可以添加到動態表中,并賦予動態索引。后續傳輸相同的頭部時,只需發送其索引。
3)霍夫曼編碼:用來壓縮頭部字段的值?;舴蚵幋a是一種可變長度編碼方法,將較短的代碼分配給出現機率高的字母,而較長的代碼分配給出現機率低的字母。這樣可以使編碼之后的字符串的平均長度降低,從而達到壓縮數據的目的。
需注意的是,HPACK只用于壓縮HTTP頭部信息。另外假如每次請求的頭部信息不一樣,也會導致動態表建立過多索引,從而導致占用太多內存。因此服務器會對一個連接上的請求數量做限制(http2_max_concurrent_Streams),避免動態表無限增大。

多路復用 (Multiplexing)
在HTTP/1中,如果想并發發送多個請求,必須創建多個TCP連接,每個 TCP 連接都要經過 TCP 握手、慢啟動以及 TLS 握手過程,這些都很耗時。瀏覽器為了減少負載,會對同一域名下的TCP連接做限制,這樣當請求量比較大時,會引起阻塞,如下圖,Stalled 阻塞已經達到356ms。如果當前請求響應遲遲不來,那么后續的請求是無法發送的,也造成了隊頭阻塞(Head-of-line blocking)的問題。

在 HTTP/2 中,有二進制分幀之后,HTTP/2 不再依賴 TCP 鏈接去實現多流并行,而是基于多個并行流復用單TCP連接的方式來實現多路復用(Multiplexing):
1)同個域名只需要占用一個 TCP 連接,單個TCP 連接可以承載任意數量的雙向流,這些流并行交錯,之間互不干擾。
2)流以消息的形式發送,而消息又由一個或多個幀組成,不同流的幀是可以亂序發送,因為可以根據幀首部的流標識重新組裝。同一個流內的幀必須是有序的。
流標識符是實現多路復用的關鍵,如下圖,服務端并行交錯地發送了兩個響應: 流1和流 3,這兩個流都是跑在一個TCP連接上,客戶端收到后,會根據相同的流標識符有序組裝成 HTTP 消息。

客戶端和服務器可以建立雙向流,服務端可以主動推送資源給客戶端。 客戶端建立的流必須是奇數號,而服務器建立的流必須是偶數號。
比如下圖,流1是客戶端向服務端請求的資源,屬于客戶端建立的流,所以該流的ID是奇數(數字 1);流 2 和 4 都是服務端主動向客戶端推送的資源,屬于服務端建立的流,所以這兩個流的 ID 是偶數(數字 2 和 4)。

HTTP/2 還可以對每個流設置不同優先級,幀頭中的“標志位”可以設置優先級,比如客戶端訪問 HTML/CSS 和圖片資源時,希望服務器先傳遞 HTML/CSS,再傳圖片,那么就可以通過設置流的優先級來實現,以此提高用戶體驗。

未完待續
很高興與你相遇!如果你喜歡本文內容,記得關注哦!
本文來自博客園,作者:poemyang,轉載請注明原文鏈接:http://www.rzrgm.cn/poemyang/p/19063734
浙公網安備 33010602011771號