WEB性能–HTTP 2.0介紹
- 2019 年 10 月 7 日
- 筆記
版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/caomage/article/details/101148656
一、HTTP 2.0介紹
HTTP2.0可以讓我們的應用更快、更簡單、更健壯!HTTP2.0把很多以前我們針對HTTP1.1想出來的歪招都一筆勾銷,把解決那些問題的方案都內置在了傳輸層中。
HTTP2.0的目的就是通過支援請求與相應的多路復用來減少延遲,通過壓縮HTTP首部欄位將協議開銷降至最低,同時增加對請求優先順序的伺服器推送的支援。
HTTP2.0不會改動HTTP的語義。HTTP方法、狀態、URI及首部欄位,這些核心概念一如往常。
二、歷史及其與SPDY的關係
SPDY是Google開發的一個實驗性協議,於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位元組。長度超過這個閾值的數據,就得分幀發送。