HTTP/2協議「多路複用」實現原理

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

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

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

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

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請求例子:web

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請求數據流「複用」的過程,很容易看的明白:
圖片描述服務器

3. 更多特性與簡介

因爲HTTP/2消息中「幀」的設計,客戶端和服務端在通訊的過程當中可以彼此瞭解更多的信息。下面再簡單說一下其餘幾點比較重要的特性,算是一個學習引導方向吧。網絡

3.1 流量控制

HTTP/2的新特性之一是基於流的流量控制。不一樣於HTTP/1.1,只要客戶端能夠處理,服務端就會盡量快的發送數據,HTTP/2提供了客戶端調整傳輸速度的能力(服務端也能夠)。WINDOW_UPDATE幀用來完成這件事情,每一個幀告訴對方,發送方想要接收多少字節,它將發送一個WINDOW_UPDATE幀以指示其更新後的處理字節能力。app

3.2 設置資源優先級和依賴關係

流的一個重要特性是能夠設置優先級和資源數據的依賴關係。HTTP/2經過流的依賴能夠實現這些功能。經過HEADERS幀和PRIORITY幀,客戶端能夠明確的告訴服務端它最須要什麼,這是經過聲明依賴關係權重實現的。

  • 依賴關係爲客戶端提供了一種能力,經過指明某些對象對另一些對象的依賴,告知服務器哪些資源應該被優先傳輸。
  • 權重讓客戶端告訴服務器如何具體肯定具備共同依賴關係對象的優先級。

3.3 服務端推送

《孫子兵法》中有一句名言:「兵馬未到,糧草先行」。服務端推送功能就能夠實現這樣一個功能。當頁面尚未開始請求具體的資源時,服務端就已經把一些資源(像css和js)已經推送到客戶端了。當瀏覽器要渲染頁面時,資源已經在緩存中了,聽起來是一件很酷的事情,實際上也正是這樣。服務端推送是經過PUSH_PROMISE幀實現的,固然其實現的細節是很是複雜的,感興趣的同窗能夠研究一下。HTTP/2的「多路複用」問題已經說明白了,還補充了一些新特性的介紹。固然想要深刻了解HTTP/2的一些原理,有太多太多的內容須要閱讀,實踐。好比「首部壓縮」算法HPACK是HTTP/2的關鍵元素之一,是HTTP/2制定開發組長時間的研究成果,其思想內容也是特別值得學習借鑑的。本節所設計到的東西只是HTTP/2協議中的冰山一角,RFC7540能夠幫助你充分了解該協議的方方面面。

相關文章
相關標籤/搜索