HTTP長連接和流水線原理是什么?什么是隊頭阻塞?HTTP/2多路復(fù)用如何解決隊頭阻塞?HTTP/3的QUIC協(xié)議做出了哪些優(yōu)化
一、面試官:請說說看HTTP1.1與HTTP1.0的主要區(qū)別是什么?
1. 連接管理:長連接與流水線處理
HTTP/1.0:默認(rèn)使用短連接,每次請求需建立新TCP連接,請求完成后立即關(guān)閉。若需長連接,需顯式設(shè)置 Connection: Keep-Alive,但兼容性差(部分代理不支持)。
HTTP/1.1:默認(rèn)啟用長連接(持久連接),允許在一個TCP連接上傳輸多個請求/響應(yīng),減少握手開銷。支持流水線(Pipelining)技術(shù),客戶端可連續(xù)發(fā)送多個請求(無需等待響應(yīng)),但服務(wù)器需按請求順序返回響應(yīng),避免隊頭阻塞。
2. Host頭域支持虛擬主機
HTTP/1.0:假設(shè)一個IP對應(yīng)唯一服務(wù)器,請求頭中無Host字段,無法支持虛擬主機技術(shù)(如多個域名共享同一IP)。
HTTP/1.1:強制要求請求頭包含 Host 字段,用于標(biāo)識目標(biāo)服務(wù)器域名。若缺失,服務(wù)器返回 400 Bad Request,解決了虛擬主機場景下的資源定位問題。
3. 緩存機制增強
HTTP/1.0:依賴 Expires(絕對時間)和 Last-Modified(最后修改時間)控制緩存,存在時鐘同步問題。緩存驗證通過 If-Modified-Since 實現(xiàn)。
HTTP/1.1:
- 引入 Cache-Control 頭(如 max-age、no-cache),支持相對時間緩存策略。
- 新增 ETag(實體標(biāo)簽)機制,通過 If-None-Match 驗證資源是否變更。
- 支持 Vary 頭,根據(jù)請求頭(如 Accept-Language)區(qū)分不同緩存版本。
4. 帶寬優(yōu)化與分塊傳輸
范圍請求:HTTP/1.1 支持 Range 頭,允許請求資源部分內(nèi)容(如斷點續(xù)傳),響應(yīng)狀態(tài)碼為 206 Partial Content。
分塊傳輸編碼(Chunked Encoding):動態(tài)生成內(nèi)容時,通過 Transfer-Encoding: chunked 分塊傳輸,無需預(yù)知完整數(shù)據(jù)大小,提升傳輸效率。
100 Continue 狀態(tài)碼:客戶端發(fā)送大請求前,先通過 Expect: 100-continue 頭詢問服務(wù)器是否接受,避免帶寬浪費。
5. 錯誤狀態(tài)碼與內(nèi)容協(xié)商
錯誤狀態(tài)碼:HTTP/1.1 新增24個狀態(tài)碼,如
- 100 Continue:(繼續(xù)請求)
- 206 Partial Content:(部分內(nèi)容)
- 409 Conflict:(資源狀態(tài)沖突)
- 410 Gone:(資源永久刪除)。
內(nèi)容協(xié)商:通過 Accept-* 系列頭(如 Accept-Language、Accept-Encoding)支持多語言/壓縮格式,服務(wù)器返回最適配版本,并通過 Vary 頭記錄協(xié)商依據(jù)。
6. 其他改進(jìn)
請求方法擴(kuò)展:HTTP/1.1 新增 OPTIONS、PUT、DELETE、TRACE 等方法,支持 RESTful API 設(shè)計。
消息傳遞優(yōu)化:支持 Trailer 頭傳遞分塊傳輸后的元數(shù)據(jù)(如校驗和),提升大文件傳輸?shù)耐暾浴?/p>
總結(jié)對比表:
特性 | HTTP/1.0 | HTTP/1.1 |
連接管理 | 短連接,需手動啟用長連接 | 默認(rèn)長連接,支持流水線 |
Host頭域 | 不支持 | 強制要求,支持虛擬主機 |
緩存機制 | 僅Expires/Last-Modified | Cache-Control/ETag/Vary |
帶寬優(yōu)化 | 不支持范圍請求 | 支持Range請求與分塊傳輸 |
狀態(tài)碼 | 16種基本狀態(tài)碼 | 新增24種,如100、206、409等 |
內(nèi)容協(xié)商 | 有限支持 | 通過Accept頭與Vary靈活適配 |
二、面試官:不錯,能不能展開聊聊HTTP長連接怎么實現(xiàn)的,它的優(yōu)點是什么,有什么不足?
1. HTTP持久連接(長連接)的詳細(xì)解析
(1) 原理
HTTP持久連接(Persistent Connection),也稱為長連接(Keep-Alive),允許客戶端和服務(wù)器在單個TCP連接上發(fā)送和接收多個HTTP請求/響應(yīng),而無需為每個請求重新建立新的連接。
① 工作流程
HTTP/1.0:默認(rèn)短連接,每個請求需建立新TCP連接,響應(yīng)后立即關(guān)閉。 如需啟用長連接,需顯式設(shè)置頭部:Connection: keep-alive。
HTTP/1.1:默認(rèn)啟用長連接,除非顯式設(shè)置Connection: close。 客戶端和服務(wù)器可復(fù)用同一TCP連接處理多個請求。
② 連接管理
保活機制:通過Keep-Alive頭部字段協(xié)商參數(shù)(如超時時間、最大請求數(shù))。 示例:Keep-Alive: timeout=5, max=100(連接空閑5秒后關(guān)閉,最多處理100個請求)。
關(guān)閉條件:
- 客戶端/服務(wù)器發(fā)送`Connection: close`頭部。
- 達(dá)到保活參數(shù)限制(如超時或最大請求數(shù))。
(2) 優(yōu)點
① 減少TCP握手開銷
- 每個TCP連接的建立需三次握手,關(guān)閉需四次揮手。
- 復(fù)用連接避免了重復(fù)握手,降低延遲(尤其對高延遲網(wǎng)絡(luò)顯著)。
② 提升資源加載效率
- 網(wǎng)頁通常需加載多個資源(HTML、CSS、JS、圖片等)。
- 長連接允許并行或串行復(fù)用同一連接,減少總加載時間。
③ 減輕服務(wù)器壓力
減少頻繁創(chuàng)建/銷毀連接的系統(tǒng)調(diào)用和內(nèi)存消耗。
④ 支持管道化(Pipelining)
HTTP/1.1允許在未收到響應(yīng)時發(fā)送多個請求(理論優(yōu)化)。
因?qū)崿F(xiàn)復(fù)雜和隊頭阻塞問題,實際使用較少,但在長連接基礎(chǔ)上提出。
(3) 局限性
① 隊頭阻塞(Head-of-Line Blocking)
- HTTP/1.1的串行請求:同一連接中的請求必須按順序處理。若前一個請求處理慢(如大文件上傳),后續(xù)請求被阻塞。
- HTTP/2的解決方案:引入多路復(fù)用(Multiplexing),允許并行處理請求。
② 資源占用問題
- 長連接占用服務(wù)器和客戶端的TCP端口和內(nèi)存資源。
- 高并發(fā)場景下,可能導(dǎo)致服務(wù)器連接數(shù)達(dá)到上限(如Linux默認(rèn)ulimit -n為1024)。
③ 連接空閑浪費
- 若連接長時間無請求,仍占用資源直到超時關(guān)閉。
- 需合理配置超時時間(如Nginx默認(rèn)keepalive_timeout 75s)。
(4) 對比不同HTTP版本
特性 | HTTP/1.0 | HTTP/1.1 | HTTP/2 |
默認(rèn)連接 | 短連接 | 長連接 | 長連接 + 多路復(fù)用 |
管道化支持 | 不支持 | 支持(但實際受限) | 支持(并行無阻塞) |
頭部壓縮 | 無 | 無 | HPACK壓縮 |
資源優(yōu)先級 | 無 | 無 | 支持優(yōu)先級流 |
2. 總結(jié)
- 核心價值:HTTP持久連接通過復(fù)用TCP連接,顯著降低延遲和服務(wù)器開銷,是Web性能優(yōu)化的基石。
- 適用場景:資源密集型頁面、API高頻調(diào)用、高并發(fā)服務(wù)。
- 權(quán)衡取舍:需平衡連接復(fù)用效率與資源占用,結(jié)合HTTP/2或HTTP/3進(jìn)一步優(yōu)化。
三、面試官:剛剛你有提到HTTP的管道化(流水線)和隊頭阻塞,能說說看是怎么回事嗎?有什么方法可以徹底解決隊頭阻塞問題?
HTTP的流水線處理(HTTP Pipelining)是HTTP/1.1引入的一種優(yōu)化技術(shù),允許客戶端通過同一TCP連接連續(xù)發(fā)送多個請求,而無需等待前一個請求的響應(yīng)返回。
1. 流水線處理的原理
(1) 與非流水線的對比
- 非流水線方式(如HTTP/1.0):客戶端需等待前一個請求的響應(yīng)完全返回后,才能發(fā)送下一個請求。例如,請求A完成后才能發(fā)送請求B,導(dǎo)致延遲疊加。
- 流水線方式(HTTP/1.1):客戶端可在未收到響應(yīng)時連續(xù)發(fā)送多個請求,服務(wù)器按接收順序依次處理并返回響應(yīng)。例如,客戶端可一次性發(fā)送請求A、B、C,服務(wù)器依次返回A、B、C的響應(yīng)。
(2) 實現(xiàn)條件
- 依賴長連接(Persistent Connection),即通過Connection: keep-alive保持TCP連接活躍。
- 服務(wù)器需支持按請求順序響應(yīng),且客戶端需能處理亂序到達(dá)的響應(yīng)(實際中較少見,多數(shù)實現(xiàn)仍按順序返回)。
HTTP1.1請求報文之間沒有記錄請求順序(如請求編號、序號)的信息,因此無法保證多個響應(yīng)之間的返回順序與發(fā)送的多個請求順序相對應(yīng),也就是說發(fā)送順序是請求1、請求2 和請求3,但由于服務(wù)端響應(yīng)速度上是請求3、請求2和請求1,因此HTTP1.1依舊要等請求1的響應(yīng)內(nèi)容準(zhǔn)備好之后才能依照 響應(yīng)1、響應(yīng)2和響應(yīng)3的順序返回。否則亂序到達(dá)的響應(yīng)就可能會交付給錯誤的請求(如將響應(yīng)3交付給了請求1)。
而上述過程中,響應(yīng)3和響應(yīng)2就被響應(yīng)1阻塞住了,這就是所謂的隊頭阻塞。HTTP的隊頭阻塞(Head-of-Line Blocking) 是指在數(shù)據(jù)傳輸過程中,某個請求或數(shù)據(jù)包的延遲或丟失導(dǎo)致后續(xù)請求/數(shù)據(jù)被阻塞的問題。
雖然理論上HTTP1.1的流水線支持一個連接并發(fā)傳輸多個請求和響應(yīng),但由于隊頭阻塞問題無法解決,因此HTTP1.1在實際應(yīng)用中不會開啟流水線,依舊是一個連接只能串行傳輸請求和響應(yīng),要等上一個請求的響應(yīng)返回了才發(fā)送下一個請求,如果要并發(fā)發(fā)送請求只能通過建立多個連接實現(xiàn)較為有限的并發(fā)。
隊頭阻塞問題在不同協(xié)議層(如HTTP/1.1、TCP)中表現(xiàn)不同,以下是詳細(xì)說明。
2. HTTP/1.1中的隊頭阻塞
HTTP/1.1即使啟用了流水線(Pipelining),客戶端可以并發(fā)的發(fā)送請求,但服務(wù)器仍需按請求順序串行的返回響應(yīng)。若第一個請求的響應(yīng)因服務(wù)器處理緩慢被阻塞,后續(xù)請求即使已處理完成,也需等待前一個響應(yīng)返回后才能被客戶端接收。
示例:請求A、B、C依次發(fā)送,若A的響應(yīng)延遲1秒,B和C的響應(yīng)即使已生成,也必須在A的響應(yīng)返回后才能被客戶端處理。
影響 :
- 頁面加載延遲:資源(如圖片、CSS)需排隊等待,拖慢整體加載速度。
- 資源利用率低:TCP連接無法被其他請求充分利用,浪費帶寬。
采用HTTP2的多路復(fù)用機制可以解決應(yīng)用層的隊頭阻塞問題。
要介紹HTTP2如何解決應(yīng)用層的隊頭阻塞,就需要介紹流(Stream)、消息(Message)和幀(Frame)的概念和他們之間的關(guān)系。
在HTTP/2中,一個流代表一個獨立的請求-響應(yīng)交互,可以包含多個消息,每個消息由多個幀組成。流具有唯一的標(biāo)識符,可以在同一個連接上并行傳輸多個流的幀,從而實現(xiàn)多路復(fù)用。
從上圖中看到:
- 1 個 TCP 連接包含一個或者多個 Stream;
- Stream 里可以包含 1 個或多個 Message,Message 對應(yīng)請求或響應(yīng),由 HTTP 頭部和包體構(gòu)成;
- Message 里包含一條或者多個 Frame,F(xiàn)rame 是 HTTP/2 的最小傳輸單位,以二進(jìn)制壓縮格式存放請求Message;
一個Message消息是由 Headers 幀和DATA 幀組成的。
在 HTTP/2 連接上,不同 Stream 的幀是可以亂序發(fā)送的(因此可以并發(fā)不同的 Stream ),因為每個幀的頭部會攜帶 Stream ID 信息,所以接收端可以通過 Stream ID 有序組裝成 HTTP 消息,而同一 Stream 內(nèi)部的幀和消息必須是嚴(yán)格有序的。
比如下圖,服務(wù)端并行交錯地發(fā)送了兩個響應(yīng): Stream 1 的響應(yīng)Message 和 Stream 3 的響應(yīng)Message,這兩個 Stream 都是跑在一個 TCP 連接上,客戶端收到后,會根據(jù)相同的 Stream ID 有序組裝成 HTTP 消息。
這樣一來,假設(shè)stream1的請求Message比stream3的請求Message先到達(dá)服務(wù)端,而stream3的響應(yīng)Message先準(zhǔn)備好,不需要等待stream1的響應(yīng)Message準(zhǔn)備好就可以發(fā)送。客戶端可以通過消息上唯一的流標(biāo)識符準(zhǔn)確的拼裝好 Stream1 和 Stream3 的響應(yīng)Message并通過唯一的流標(biāo)識符交付給對應(yīng)的請求從而解決隊頭阻塞問題,提高并發(fā)。
四、面試官:能不能說說看HTTP/2相比HTTP/1.1還有哪些地方做了提升?
HTTP/2 在 HTTP/1.1 的基礎(chǔ)上通過多項技術(shù)改進(jìn)顯著提升了性能,主要優(yōu)化點如下:
1. 多路復(fù)用
HTTP/2 的多路復(fù)用(Multiplexing) 是其核心特性之一,通過在一個 TCP 連接上并行傳輸多個請求和響應(yīng),徹底解決了 HTTP/1.1 的隊頭阻塞問題。以下是其原理及性能提升的詳細(xì)分析:
(1) 流(Stream)與幀(Frame)
- 流:HTTP/2 連接中的邏輯通道,每個流獨立傳輸雙向的幀序列(請求或響應(yīng))。
- 幀:數(shù)據(jù)傳輸?shù)淖钚挝唬鳂?biāo)識符(Stream ID)和類型(如 HEADERS、DATA)。
- 實現(xiàn)方式:多個流的幀可交錯傳輸,客戶端和服務(wù)器按流 ID 重組數(shù)據(jù),無需按順序等待。
(2) 與 HTTP/1.1 的對比
- HTTP/1.1請求/響應(yīng)需嚴(yán)格串行化,一個請求延遲會導(dǎo)致后續(xù)請求阻塞(隊頭阻塞)。
- HTTP/2同一 TCP 連接上可并行處理多個請求,流之間相互獨立,互不干擾。
HTTP2的多路復(fù)用帶來了如下提升。
① 消除隊頭阻塞
- 問題場景:在 HTTP/1.1 中,若請求 A 的響應(yīng)延遲,后續(xù)請求 B、C 需排隊等待。
- 解決方案:HTTP/2 的多路復(fù)用允許請求 B、C 的幀與請求 A 的幀交錯傳輸,即使 A 延遲,B 和 C 的響應(yīng)仍可被優(yōu)先處理。
② 減少 TCP 連接數(shù)
- HTTP/1.1:瀏覽器通常為每個域名建立 6-8 個 TCP 連接以并行請求資源。
- HTTP/2:僅需一個連接即可并行傳輸所有請求,降低連接建立和維護(hù)的開銷(如三次握手、TLS 握手)。
③ 提升傳輸效率
- 資源利用率:TCP 連接的帶寬被多個流共享,避免單個請求占用TCP連接內(nèi)的全部資源。
- 延遲優(yōu)化:在弱網(wǎng)環(huán)境下,多路復(fù)用可減少 30%-50% 的頁面加載時間。例如,請求一個大 JS 文件和一個小 CSS 文件時,HTTP/2 可并行傳輸,而 HTTP/1.1 需串行等待。
④ 節(jié)省服務(wù)器資源
減少并發(fā)連接數(shù)可降低服務(wù)器內(nèi)存和 CPU 的消耗,提升高負(fù)載場景下的穩(wěn)定性。
2. 頭部壓縮
HTTP/2 的頭部壓縮是通過 HPACK 算法實現(xiàn)的核心優(yōu)化技術(shù),旨在減少 HTTP 頭部的冗余數(shù)據(jù),提升傳輸效率。以下是其原理及優(yōu)點的詳細(xì)說明:
(1) HPACK 算法
核心思想:通過靜態(tài)表、動態(tài)表和哈夫曼編碼,消除重復(fù)的頭部字段,減少傳輸體積。
實現(xiàn)方式:
- 靜態(tài)表(Static Table):預(yù)定義 61 個常用頭部字段(如 `:method`、`:path`、`content-type`),直接用索引號代替完整字段名。例如,`:method: GET` 可編碼為索引 `2`,僅需傳輸 1 字節(jié)。
- 動態(tài)表(Dynamic Table):在會話過程中動態(tài)存儲客戶端與服務(wù)器交換的自定義頭部字段,后續(xù)請求直接引用索引。
例如,首次發(fā)送 `user-agent: Mozilla/5.0` 后,后續(xù)請求只需發(fā)送其動態(tài)表索引。
- 哈夫曼編碼(Huffman Coding):對頭部字段的鍵和值進(jìn)行字符級壓縮,高頻字符用短編碼,低頻字符用長編碼。例如,字母 `e` 出現(xiàn)頻率高,編碼為 `010`,而 `z` 編碼為 `111111`。
頭部壓縮的總和效果如下圖所示:
(2) 頭部壓縮的優(yōu)點
① 顯著減少帶寬消耗
- 通過消除冗余頭部字段(如重復(fù)的 Cookie、User-Agent),降低傳輸數(shù)據(jù)量,尤其適用于移動端或低帶寬環(huán)境。
- 例如,一個包含 20 個請求的頁面,HTTP/1.1 的頭部總大小可能達(dá) 10KB,而 HTTP/2 壓縮后可降至 1KB 以下。
② 降低延遲,提升并發(fā)性能
- 減少 TCP 連接數(shù):頭部壓縮允許單個連接承載更多請求。
- 加速首屏加載:關(guān)鍵資源(如 HTML、CSS)的頭部壓縮后,傳輸時間縮短,頁面渲染更快。
3. 服務(wù)器推送
HTTP/2 的服務(wù)器推送(Server Push) 是一種允許服務(wù)器主動向客戶端發(fā)送資源的技術(shù),無需等待客戶端顯式請求。以下是其特性與優(yōu)點的詳細(xì)說明:
(1) 主動推送機制
服務(wù)器在客戶端請求一個資源(如 HTML 頁面)時,可主動推送與之關(guān)聯(lián)的其他資源(如 CSS、JS、圖片)。
示例:客戶端請求 index.html,服務(wù)器同時推送 style.css 和 script.js,減少后續(xù)請求的往返時間(RTT)。
(2) 資源預(yù)判與優(yōu)先級
- 服務(wù)器可根據(jù)業(yè)務(wù)邏輯預(yù)判客戶端需要的資源(如通過 Link 頭部聲明推送列表)。
- 支持設(shè)置推送資源的優(yōu)先級,確保關(guān)鍵資源(如首屏 CSS)優(yōu)先傳輸。
(3) 服務(wù)器推送的優(yōu)點與局限性
① 顯著減少延遲(優(yōu)點)
- 減少往返次數(shù):通過提前推送資源,客戶端無需額外發(fā)起請求,降低頁面加載時間。
- 加速首屏渲染:關(guān)鍵資源(如 CSS、JS)的提前到達(dá)可更快完成頁面渲染。
② 僅支持靜態(tài)資源(局限)
服務(wù)器推送無法傳輸動態(tài)生成的內(nèi)容(如實時數(shù)據(jù)),需結(jié)合 WebSocket 或 SSE 實現(xiàn)實時通信。
4. 安全機制提升
- 協(xié)議要求:HTTP/2 規(guī)范(RFC 7540)建議與 TLS 1.2 或更高版本 結(jié)合使用,且必須支持 前向安全(Forward Secrecy) 和 服務(wù)器名稱指示(SNI)。
- TLS 1.3 支持:HTTP/2 結(jié)合 TLS 1.3 時,握手僅需 1 個往返時間(RTT),且通過臨時密鑰(Ephemeral Key)實現(xiàn)前向安全,即使長期密鑰泄露,歷史通信也無法被解密。
- 會話復(fù)用:支持基于會話 ID 或票據(jù)(Session Ticket)的快速握手,減少重復(fù)連接的加密開銷。
- 二進(jìn)制分幀:HTTP/2 使用二進(jìn)制格式而非明文傳輸,降低中間設(shè)備(如代理、防火墻)因解析文本協(xié)議導(dǎo)致的注入攻擊或篡改風(fēng)險。
- 頭部壓縮安全:HPACK 算法通過動態(tài)表和哈夫曼編碼壓縮頭部,避免明文頭部字段被竊取或篡改。
五、面試官:HTTP/2有什么局限性?HTTP/3基于UPD的QUIC協(xié)議如何提升連接效率??
1. HTTP/2 的缺陷
(1) TCP層面的隊頭阻塞
HTTP/2 通過 Stream 的并發(fā)能力,解決了 HTTP/1 隊頭阻塞的問題,看似很完美了,但是 HTTP/2 還是存在“隊頭阻塞”的問題,只不過問題不是在 HTTP 這一層面,而是在 TCP 這一層。
HTTP/2 是基于 TCP 協(xié)議來傳輸數(shù)據(jù)的,TCP 是字節(jié)流協(xié)議,TCP 層必須保證收到的字節(jié)數(shù)據(jù)是完整且連續(xù)的,這樣內(nèi)核才會將緩沖區(qū)里的數(shù)據(jù)返回給 HTTP 應(yīng)用,那么當(dāng)「前 1 個字節(jié)數(shù)據(jù)」沒有到達(dá)時,后收到的字節(jié)數(shù)據(jù)只能存放在內(nèi)核緩沖區(qū)里,只有等到這 1 個字節(jié)數(shù)據(jù)到達(dá)時,HTTP/2 應(yīng)用層才能從內(nèi)核中拿到數(shù)據(jù),這就是 HTTP/2 隊頭阻塞問題。
圖片
因為 TCP 是字節(jié)流協(xié)議,TCP 層必須保證收到的字節(jié)數(shù)據(jù)是完整且有序的,如果序列號較低的 TCP 段在網(wǎng)絡(luò)傳輸中丟失了,即使序列號較高的 TCP 段已經(jīng)被接收了,應(yīng)用層也無法從內(nèi)核中讀取到這部分?jǐn)?shù)據(jù)。從 HTTP 視角看,就是請求被阻塞了。
舉個例子,如下圖:
圖中發(fā)送方發(fā)送了很多個 Packet,每個 Packet 都有自己的序號,你可以認(rèn)為是 TCP 的序列號,其中 Packet 3 在網(wǎng)絡(luò)中丟失了,即使 Packet 4~6 被接收方收到后,由于內(nèi)核中的 TCP 數(shù)據(jù)不是連續(xù)的,于是接收方的應(yīng)用層就無法從內(nèi)核中讀取到,只有等到 Packet 3 重傳后,接收方的應(yīng)用層才可以從內(nèi)核中讀取到數(shù)據(jù),這就是 HTTP/2 的隊頭阻塞問題,是在 TCP 層面發(fā)生的。
所以,一旦發(fā)生了丟包現(xiàn)象,就會觸發(fā) TCP 的重傳機制,這樣在一個 TCP 連接中的所有的 HTTP 請求都必須等待這個丟了的包被重傳回來。
(2) TCP 與 TLS 的握手時延遲
發(fā)起 HTTP 請求時,需要經(jīng)過 TCP 三次握手和 TLS 四次握手(TLS 1.2)的過程,因此共需要 3 個 RTT 的時延才能發(fā)出請求數(shù)據(jù)。
另外,TCP 由于具有「擁塞控制」的特性,所以剛建立連接的 TCP 會有個「慢啟動」的過程,它會對 TCP 連接產(chǎn)生“減速”效果。
(3) 網(wǎng)絡(luò)遷移需要重新連接
一個 TCP 連接是由四元組(源 IP 地址,源端口,目標(biāo) IP 地址,目標(biāo)端口)確定的,這意味著如果 IP 地址或者端口變動了,就會導(dǎo)致需要 TCP 與 TLS 重新握手,這不利于移動設(shè)備切換網(wǎng)絡(luò)的場景,比如 4G 網(wǎng)絡(luò)環(huán)境切換成 WiFi。
這些問題都是 TCP 協(xié)議固有的問題,無論應(yīng)用層的 HTTP/2 在怎么設(shè)計都無法避免。
HTTP3把傳輸層協(xié)議替換成 UDP,從傳輸層徹底進(jìn)行優(yōu)化。
2. HTTP/3 的優(yōu)化
(1) 無隊頭阻塞
QUIC 協(xié)議也有類似 HTTP/2 Stream 與多路復(fù)用的概念,也是可以在同一條連接上并發(fā)傳輸多個 Stream,Stream 可以認(rèn)為就是一條 HTTP 請求。
由于 QUIC 使用的傳輸協(xié)議是 UDP,UDP 不關(guān)心數(shù)據(jù)包的順序,如果數(shù)據(jù)包丟失,UDP 也不關(guān)心。
不過 QUIC 協(xié)議會保證數(shù)據(jù)包的可靠性,每個數(shù)據(jù)包都有一個序號唯一標(biāo)識。當(dāng)某個流中的一個數(shù)據(jù)包丟失了,即使該流的其他數(shù)據(jù)包到達(dá)了,數(shù)據(jù)也無法被 HTTP/3 讀取,直到 QUIC 重傳丟失的報文,數(shù)據(jù)才會交給 HTTP/3。
而其他流的數(shù)據(jù)報文只要被完整接收,HTTP/3 就可以讀取到數(shù)據(jù)。可以認(rèn)為HTTP/3 把 HTTP/2 在應(yīng)用層上的多個流的概念轉(zhuǎn)移到了傳輸層上,解決了傳輸層的隊頭阻塞問題。
(2) 更快的連接建立
對于 HTTP/1 和 HTTP/2 協(xié)議,TCP 和 TLS 是分層的,分別屬于內(nèi)核實現(xiàn)的傳輸層、OpenSSL 庫實現(xiàn)的表示層,因此它們難以合并在一起,需要分批次來握手,先 TCP 握手,再 TLS 握手。
HTTP/3 在傳輸數(shù)據(jù)前雖然需要 QUIC 協(xié)議握手,這個握手過程只需要 1 RTT,握手的目的是為確認(rèn)雙方的「連接 ID」,連接遷移就是基于連接 ID 實現(xiàn)的。
但是 HTTP/3 的 QUIC 協(xié)議并不是與 TLS 分層,而是 QUIC 內(nèi)部包含了 TLS,它在自己的幀會攜帶 TLS 里的“記錄”,再加上 QUIC 使用的是 TLS/1.3,因此僅需 1 個 RTT 就可以「同時」完成建立連接與密鑰協(xié)商,如下圖:
甚至,在第二次連接的時候,應(yīng)用數(shù)據(jù)包可以和 QUIC 握手信息(連接信息 + TLS 信息)一起發(fā)送,達(dá)到 0-RTT 的效果。
如下圖右邊部分,HTTP/3 當(dāng)會話恢復(fù)時,有效負(fù)載數(shù)據(jù)與第一個數(shù)據(jù)包一起發(fā)送,可以做到 0-RTT(下圖的右下角):
(3) 連接遷移
基于 TCP 傳輸協(xié)議的 HTTP 協(xié)議,由于是通過四元組(源 IP、源端口、目的 IP、目的端口)確定一條 TCP 連接。
那么當(dāng)移動設(shè)備的網(wǎng)絡(luò)從 4G 切換到 WIFI 時,意味著 IP 地址變化了,那么就必須要斷開連接,然后重新建立連接。而建立連接的過程包含 TCP 三次握手和 TLS 四次握手的時延,以及 TCP 慢啟動的減速過程,給用戶的感覺就是網(wǎng)絡(luò)突然卡頓了一下,因此連接的遷移成本是很高的。
而 QUIC 協(xié)議沒有用四元組的方式來“綁定”連接,而是通過連接 ID 來標(biāo)記通信的兩個端點,客戶端和服務(wù)器可以各自選擇一組 ID 來標(biāo)記自己,因此即使移動設(shè)備的網(wǎng)絡(luò)變化后,導(dǎo)致 IP 地址變化了,只要仍保有上下文信息(比如連接 ID、TLS 密鑰等),就可以“無縫”地復(fù)用原連接,消除重連的成本,沒有絲毫卡頓感,達(dá)到了連接遷移的功能。