您當前的位置:首頁 > 繪畫

WEB效能(5)--HTTP 2.0介紹

作者:由 炒醬 發表于 繪畫時間:2019-09-22

一、HTTP 2。0介紹

HTTP2。0可以讓我們的應用更快、更簡單、更健壯!HTTP2。0把很多以前我們針對HTTP1。1想出來的歪招都一筆勾銷,把解決那些問題的方案都內建在了傳輸層中。

HTTP2。0的目的就是透過支援請求與相應的多路複用來減少延遲,透過壓縮HTTP首部欄位將協議開銷降至最低,同時增加對請求優先順序的伺服器推送的支援。

HTTP2。0不會改動HTTP的語義。HTTP方法、狀態、URI及首部欄位,這些核心概念一如往常。

二、歷史及其與SPDY的關係

SPDY是谷歌開發的一個實驗性協議,於2009年年中釋出,其主要目標是透過解決HTTP1。1中廣為人知的一些效能限制,來減少網頁的載入延遲。SPDY引入了一個新的二進位制分幀資料層,以實現多向請求和響應、優先次序、最小化及消除不必要的網路延遲,目的是更有效利用底層TCP連線。

幾年後的2012年,這個新的實驗性協議得到了Chrome、Firefox和Opera的支援,很多大型網站都對相容客戶端提供SPDY會話。換句話說,SPDY在被行業採用並證明能夠大幅提升效能值周,已經具備了成為一個標準的條件。最終,HTTP-WG在2012年吸取了SPDY的經驗教訓,並在此基礎上制定了官方標準。

三、走向HTTP2。0

SPDY是HTTP2。0的催化劑,但是SPDY並非HTTP2。0。以下是HTTP2。0宣言草稿,這份宣言明確了該協議的範圍和關鍵設計要求:

相對於使用TCP的HTTP1。1,使用者在大多數情況下的感知延遲要有實質上、可度量的改進;

解決HTTP中的“隊首阻塞”問題;

並行操作無需與伺服器建立多個連線,從而改進TCP的利用率,特別是擁塞控制方面;

保持HTTP1。1的語義,利用現有文件,包括但不限於:HTTP方法、狀態碼、URI以及首部欄位;

明確規定HTTP2。0如何與HTTP1。x互操作,特別是在中間介質上;

明確指出所有新的可擴充套件機制以及適當的擴充套件策略。

四、設計和技術目標

HTTP1。x的設計初衷主要是實現要簡單:HTTP0。9只用一行協議就啟動了全球資訊網;然而實現簡單是以犧牲應用效能為代價的,而這正是HTTP2。0要致力與解決的。HTTP2。0透過支援首部欄位壓縮和在同一連線上傳送多個併發訊息,讓應用更有效的利用網路資源,減少感知的延遲時間。而且,它還支援伺服器到客戶端的主動推送機制。

4。1 二進位制分幀層

HTTP2。0效能增強的核心,全在於新增的二進位制分幀層,它定義瞭如何封裝HTTP訊息並在客戶端與伺服器之間傳輸。這裡所謂的“層”,指的是位於套接字介面與應用可見高層HTTP API之間的一個新機制:HTTP語義,包括各種動詞、方法、首部,都不受影響,不同的是傳輸期間對它們的編碼方式變了。HTTP1。x以換行符作為純文字的分隔符,而HTTP2。0將所有傳輸的資訊分割為更小的訊息和幀,並對它們採用二進位制格式的編碼。

這樣一來,客戶端和伺服器為了相互理解,必須都使用新的二進位制編碼機制:HTTP1。x客戶端無法理解只支援HTTP2。0的伺服器,反之亦然。不過不要緊,現有的應用不必擔心這些變化,因為客戶端和伺服器會替它們完成必要的分幀工作。

HTTPS是二進位制分幀的另一個典型示例:所有HTTP訊息都以透明的方式為我們編碼和解碼,從而實現客戶端與伺服器安全通訊,但不必對應用進行任何修改。HTTP2。0的工作原理差不多也是這樣。

4。2 流、訊息和幀

新的二進位制分幀機制改變了客戶端與伺服器之間互動資料的方式。為了說明這個過程,我們需要了解HTTP2。0的幾個新概念:

已建立的連線上的雙向位元組流。

訊息

與邏輯訊息對應的完整的一系列資料幀。

HTTP2。0通訊的最小單位,每個幀包含幀首部,至少也會標識出當前幀所屬的流。

HTTP2。0通訊都在一個連線上完成,這個連線可以承載任意資料量的雙向資料流。相應地,每個資料流以訊息的形式傳送,而訊息由一或多個幀組成,這些幀可以亂序傳送,然後再根據每個幀首部的流識別符號重新組裝。HTTP2。0的所有幀都採用二進位制編碼,所有首部資料都會被壓縮。

這簡簡單單的幾句話裡濃縮了大量的資訊:

所有通訊都在一個TCP連線上完成;

流是連線中的一個虛擬通道,可以承載雙向的訊息。每個流都有一個唯一的整數識別符號;

訊息是指邏輯上的HTTP訊息,比如請求、相應等,由一或多個幀組成;

幀是最小的通訊單位,承載這特定型別的資料,如HTTP首部、負荷等;

簡言之,HTTP2。0把HTTP協議通訊的基本單位縮小為一個一個的幀,這些幀對應著邏輯流中的訊息。相應地,很多流可以並行的在同一個TCP連線上交換訊息。

4。3 多向請求與響應

在HTTP1。x中,如果客戶端想傳送多個並行的請求以及改進效能,那麼必須使用多個TCP連線。這是HTTP1。x交付模型的直接結果,該模型會保證每個連線每次只交付一個響應(多個響應必須排隊)。更糟糕的是,這種模型也會導致隊首阻塞,從而造成底層TCP連線的效率低下。

HTTP2。0中新的二進位制分幀層突破了這些限制,實現了多向請求和響應:客戶端和伺服器可以把HTTP訊息分解為互不依賴的幀,然後亂序傳送,最後再在另一端把它們重新組合起來。

把HTTP訊息分解為獨立的幀,交錯傳送,然後在另一端重新組裝是HTTP2。0最重要的一項增強。事實上,這個機制會在整個Web技術棧中引發一系列連鎖反應,從而帶來巨大的效能提升,因為:

可以並行交錯的傳送請求,請求之間互不影響;

可以並行交錯的傳送響應,響應之間互不干擾;

只使用一個連線即可並行傳送多個請求和響應;

消除不必要的延遲,從而減少頁面載入的時間;

不必再為繞過HTTP1。x限制而多做很多工作。

總之,HTTP2。0的二進位制分幀機制解決了HTTP1。x中存在的隊首阻塞問題,也消除了並行處理和傳送請求及響應時對多個連線的依賴。結果就是應用速度更快、開發更簡單、部署成本更低。

支援多向請求和響應,可以省掉對HTTP1。x限制所費的那些工作,比如拼接檔案、圖片精靈、域名分割槽。類似地,透過減少TCP連線的數量,HTTP2。0也會減少客戶端和伺服器的CPU及記憶體佔用。

4。4 請求優先順序

把HTTP訊息分解為很多獨立的幀之後,就可以透過最佳化這些幀的交錯和傳輸順序,進一步提升效能。為了做到這一點,每個流都可以帶有一個31位元的優先值:

0表示最高優先順序;

(2^31)-1表示最低優先順序。

有了這個優先值,客戶端和伺服器就可以在處理不同的流時採用不同的策略,以最優的方式傳送流、訊息和幀。具體來講,伺服器可以根據流的優先順序,控制資源分配(CPU、記憶體、頻寬),而在響應資料準備好之後,優先將高優先順序的幀傳送給客戶端。

瀏覽器在渲染頁面時,並非所有資源都具有相同的優先順序:HTML文件本身對構建DOM不可或缺,CSS對構建CSSOM不可或缺,而DOM和CSSOM的構建都可能會受到JavaScript資源的阻塞,其他資源(如圖片)的優先順序都可以降低。為加快頁面載入的速度,所有現代瀏覽器都會基於資源的型別以及它在頁面中的位置排定請求的優先次序,甚至透過之前的訪問來學習優先順序模式——比如,之前的渲染如果被某些資源阻塞了,那麼同樣的資源在下一次訪問時可能就會被賦予更高的優先順序。

4。5 每個來源一個連線

有了新的分幀機制後,HTTP2。0不再依賴多個TCP連線去實現多流並行了。現在,每個資料流都拆分成很多幀,而這些幀可以交錯,還可以分別優先順序。於是,所有HTTP2。0連線都是持久化的,而且客戶端與伺服器之間也只需要一個連線即可。

每個來源一個連線顯著減少了相關資源的佔用:連線路徑上的套接字管理工作量少了,記憶體佔用少了,連線的吞吐量大了。此外,從上到下所有層面上也都獲得了相應的好處:

所有話劇流的優先次序始終如一;

壓縮上下文單一使得壓縮效果更好;

由於TCP連線減少而使網路擁塞狀況得以改觀;

慢啟動時間減少,擁塞和丟包回覆速度更快。

4。6 流量控制

在同一個TCP上傳輸多個數據流,就意味著要共享頻寬。標定資料流的優先順序有助於按序交付,但只有優先順序還不足以確定多個數據流或多個連線間的資源分配。為解決這個問題,HTTP2。0為資料流和連線的流量控制提供了一個簡單的機制:

流量控制基於每一跳進行,而非端到端的控制;

流量控制基於視窗更新幀進行,即接收方廣播自己準備接收某個資料流的多少位元組,以及整個連線要接收多少位元組;

流量控制視窗大小透過WINDOW_UPDATE幀更新,這個欄位指定了流ID和視窗大小遞增值;

流量控制有方向性,即接收放可能根據自己的情況為每個流乃至整個連線設定任意視窗大小;

流量控制可以由接收方禁用,包括針對個別的流和針對整個連線。

HTTP2。0建立連線之後,客戶端與伺服器交換SETTINGS幀,目的是設定雙向的流量控制視窗大小。除此之外,任何一端都可以選擇禁用個別流或整個連線的流量控制。

4。7 伺服器推送

HTTP2。0新增的一個強大的新功能,就是伺服器可以對一個客戶端請求傳送多個響應。換句話說,除了對最初請求的響應外,伺服器還可以額外想客戶端推送資源,而無需客戶端明確的請求。

建立HTTP2。0連線後,客戶端與伺服器交換SETTINGS幀,藉此可以限定雙向併發的流的最大數量。因此,客戶端可以限定推送流的數量,或者透過設定為0而完全禁用伺服器推送。

所有推送的資源都遵守同源策略。換句話說,伺服器不能隨便將第三方資源推送給客戶端,而必須是經過雙方確認才行。

4。8 首部壓縮

HTTP的每次通訊都會攜帶一組首部,用於描述傳輸的資源及其屬性。在HTTP1。x中這些元資料都是以純文字形式傳送的,通常會給每個請求增加500-800位元組的負擔。如果算上Cookie,增加的負擔更重。為減少這些,HTTP2。0會壓縮首部元資料。 HTTP2。0在客戶端和伺服器端使用“首部表”來跟蹤和儲存之前傳送的鍵值對,對於相同的資料,不再透過每次請求和響應傳送; 首部表在HTTP2。0的連線存續期內始終存在,有客戶端和伺服器共同更新; 每個新的首部鍵值對要麼被追加到當前表的末尾,要麼替換表中之前的值。

於是,HTTP2。0連線的兩端都知道已經發送了哪些首部。請求與響應首部的定義在HTTP2。0中基本沒有改變,只是所有的首部健必須全部小寫。

五、二進位制分幀簡介

HTTP2。0的根本改進還是新增的長度前置的二進位制分幀層。與HTTP1。x使用換行符分隔純文字不同,二進位制分幀層更加簡潔,透過程式碼處理起來更簡單也更有效。

建立了HTTP2。0連線後,客戶端與伺服器會透過交換幀來通訊,幀是基於這個新協議通訊的最小單位。所有幀都共享一個8位元組的首部,其中包含幀的長度、型別、標誌,還有一個保留位和一個31位的流識別符號。

16位的長度字首意味著一幀大約可以攜帶64KB資料,不包括8位元組的首部;

8位型別欄位決定如何解釋幀其餘部分的內容;

8位的標誌欄位允許不同的幀型別定義特定於幀的訊息標誌;

1位的保留欄位始終為0;

31位的流識別符號唯一標識HTTP2。0的流。

知道了HTTP2。0規定的這個共享的幀首部,就可以自己編寫一個簡單的解析器,透過分析HTTP2。0的位元組流,根據每個幀的前8位元組找到幀的型別、標識和長度。知道了幀型別,解析器就知道該如何解釋幀的其餘內容了。HTTP2。0規定了如下幀型別:

DATA:用於傳輸HTTP訊息體;

HEADERS:用於傳輸關於流的額外的首部欄位;

PRIORITY:用於指定或重新指定引用資源的優先順序;

RST_STREAM:用於通知流的非正常終止;

SETTINGS:用於通知兩端通訊方式的配置資料;

PUSH_PROMISE:用於發出建立流和伺服器引用資源的要約;

PING:用於計算往返時間,執行活性檢查;

GOAWAY:用於通知對端停止在當前連線中建立流;

WINDOW_UPDATE:用於針對個別流或個別連線實現流量控制;

CONTINUATION:用於繼續一系列首部塊片段。

5。1 發起新流

在傳送應用資料之前,必須建立一個新流並隨之傳送相應的元資料,比如流優先順序、HTTP首部等。HTTP2。0協議規定客戶端和伺服器都可以發起新流,因此有兩種可能: 客戶端透過傳送HEADERS幀來發起新流,這個幀裡包含有新流ID的公用首部、可選的31位優先值,以及一組HTTP鍵值對首部; 伺服器透過PUSH_PROMISE幀來發起推送流,這個幀與HEADERS幀等效,但它包含要約流ID,沒有優先值。

這兩種幀的型別欄位都只用於溝通新流的元資料,淨荷會在DATA幀中單獨傳送。由於流的元資料與應用資料是單獨傳送的,因此客戶端和伺服器可以分別給他們設定不同的優先順序。

5。2 傳送應用資料

建立併發送HTTP首部之後,接下來就是利用DATA幀傳送應用資料。應用資料可以分為多個DATA幀,最後一幀要翻轉幀首部的END_STREAM欄位。

資料淨荷不會被另行編碼或壓縮。編碼方式取決於應用或伺服器,純文字、gzip壓縮、圖片或影片壓縮格式都可以。

從技術上說,DATA幀的長度欄位決定了每幀的資料淨荷最多可大65535位元組。可是,為了減少隊首阻塞,HTTP2。0標準要求DATA幀不能超過16383位元組。長度超過這個閾值的資料,就得分幀傳送。

標簽: HTTP2  客戶端  首部  http  連線