HTTP/2協議“多路複用”實現原理

1.HTTP/2較HTTP/1.1優化亮點

HTTP/2是一個二進制協議,其基於“幀”的結構設計,改進了很多HTTP/1.1痛點問題。下面列舉一些最常被津津樂道的改進之處:

  • 多路複用的流
  • 頭部壓縮
  • 資源優先級和依賴設置
  • 服務器推送
  • 流量控制
  • 重置消息

以上列舉的每一項都值得做深入細緻的研究,這裏就只針對“多路複用”功能的實現進行深入的學習。

2.“多路複用”的原理解析

2.1 什麼是多路複用?

網絡上有一張圖能清晰的解釋這個問題:
圖片描述
HTTP/1.1協議的請求-響應模型大家都是熟悉的,我們用“HTTP消息”來表示一個請求-響應的過程,那麼HTTP/1.1中的消息是“管道串形化”的:只有等一個消息完成之後,才能進行下一條消息;而HTTP/2中多個消息交織在了一起,這無疑提高了“通信”的效率。這就是多路複用:在一個HTTP的連接上,多路“HTTP消息”同時工作

2.2 爲什麼HTTP/1.1不能實現“多路複用”?

簡單回答就是:HTTP/2是基於二進制“幀”的協議,HTTP/1.1是基於“文本分割”解析的協議。
看一個HTTP/1.1簡單的GET請求例子:

GET / HTTP/1.1
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.9,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:imooc_uuid=b2076a1d-6a14-4cd5-91b0-17a9a2461cf4; imooc_isnew_ct=1517447702; imooc_isnew=2; zg_did=%7B%22did%22%3A%20%221662d799f3f17d-0afe8166871b85-454c092b-100200-1662d799f4015b%22%7D; loginstate=1; apsid=Y4ZmEwNGY3OTUwMTdjZTk0ZTc4YzBmYThmMDBmZDYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDEwNzI4OQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5NTMzNjIzNjVAcXEuY29tAAAAAAAAAAAAAAAAAAAAADBmNmM5MzczZTVjMTk3Y2VhMDE2ZjUxNmQ0NDUwY2IxIDPdWyAz3Vs%3DYj; Hm_lvt_fb538fdd5bd62072b6a984ddbc658a16=1541222935,1541224845; Hm_lvt_f0cfcccd7b1393990c78efdeebff3968=1540010199,1541222930,1541234759; zg_f375fe2f71e542a4b890d9a620f9fb32=%7B%22sid%22%3A%201541297212384%2C%22updated%22%3A%201541297753524%2C%22info%22%3A%201541222929083%2C%22superProperty%22%3A%20%22%7B%5C%22%E5%BA%94%E7%94%A8%E5%90%8D%E7%A7%B0%5C%22%3A%20%5C%22%E6%85%95%E8%AF%BE%E7%BD%91%E6%95%B0%E6%8D%AE%E7%BB%9F%E8%AE%A1%5C%22%2C%5C%22%E5%B9%B3%E5%8F%B0%5C%22%3A%20%5C%22web%5C%22%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%22Jph3DQ809OQ%2C%22%7D; PHPSESSID=h5jn68k1fcaadn61bpoqa9hch2; cvde=5be7a057c314b-1; IMCDNS=1
Host:www.imooc.com
Referer:https://www.imooc.com/
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36

以上就是HTTP/1.1發送請求消息的文本格式:以換行符分割每一條key:value的內容,解析這種數據用不着什麼高科技,相反的,解析這種數據往往速度慢且容易出錯。“服務端”需要不斷的讀入字節,直到遇到分隔符(這裏指換行符,代碼中可能使用/n或者/r/n表示),這種解析方式是可行的,並且HTTP/1.1已經被廣泛使用了二十多年,這事已經做過無數次了,問題一直都是存在的:

  • 一次只能處理一個請求或響應,因爲這種以分隔符分割消息的數據,在完成之前不能停止解析。
  • 解析這種數據無法預知需要多少內存,這會帶給“服務端”很大的壓力,因爲它不知道要把一行要解析的內容讀到多大的“緩衝區”中,在保證解析效率和速度的前提下:內存該如何分配?

2.3 HTTP/2幀結構設計和多路複用實現

前邊提到:HTTP/2設計是基於“二進制幀”進行設計的,這種設計無疑是一種“高超的藝術”,因爲它實現了一個目的:一切可預知,一切可控
幀是一個數據單元,實現了對消息的封裝。下面是HTTP/2的幀結構:
圖片描述
幀的字節中保存了不同的信息,前9個字節對於每個幀都是一致的,“服務器”解析HTTP/2的數據幀時只需要解析這些字節,就能準確的知道整個幀期望多少字節數來進行處理信息。我們先來了解一下幀中每個字段保存的信息:

名稱 長度 描述
Length 3 字節 表示幀負載的長度,默認最大幀大小2^14
Type 1 字節 當前幀的類型,下面會做介紹
Flags 1 字節 具體幀的標識
R 1 字節 保留位,不需要設置,否則可能帶來嚴重後果
Stream Identifier 31 位 每個流的唯一ID
Frame Payload 不固定 真實幀的長度,真實長度在Length中設置

如果使用HTTP/1.1的話,你需要發送完上一個請求,才能發送下一個;由於HTTP/2是分幀的,請求和響應可以交錯甚至可以複用。
爲了能夠發送不同的“數據信息”,通過幀數據傳遞不同的內容,HTTP/2中定義了10種不同類型的幀,在上面表格的Type字段中可對“幀”類型進行設置。下表是HTTP/2的幀類型:

名稱 ID 描述
DATA 0x0 傳輸流的核心內容
HEADERS 0x1 包含HTTP首部,和可選的優先級參數
PRIORITY 0x2 指示或者更改流的優先級和依賴
RST_STREAM 0x3 允許一端停止流(通常是由於錯誤導致的)
SETTINGS 0x4 協商連接級參數
PUSH_PROMISE 0x5 提示客戶端,服務端要推送些東西
PING 0x6 測試連接可用性和往返時延(RTT)
GOAWAY 0x7 告訴另外一端,當前端已結束
WINDOW_UPDATE 0x8 協商一端要接收多少字節(用於流量控制)
CONTINUATION 0x9 用以拓展HEADER數據塊

有了以上對HTTP/2幀的瞭解,我們就可以解釋多路複用是怎樣實現的了,不過在這之前我們先來了解“流”的概念:HTTP/2連接上獨立的、雙向的幀序列交換。流ID(幀首部的6-9字節)用來標識幀所屬的流
下面兩張圖分別表示了HTTP/2協議上POST請求數據流“複用”的過程,很容易看的明白:
圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章