現(xiàn)在用谷歌瀏覽器看 B 站視頻,默認(rèn)是用 HTTP/2 協(xié)議,它相比 HTTP/1.1 性能提高很多,但是其實(shí)看 B 站視頻還能更快!
因?yàn)?B 站部分視頻服務(wù)器支持使用 QUIC 協(xié)議觀看視頻,QUIC 是基于 UDP 傳輸協(xié)議實(shí)現(xiàn)的,而且最新的 HTTP/3 使用的正是 QUIC 協(xié)議,它相比 HTTP/2 性能其實(shí)更好,觀看視頻體驗(yàn)更佳,特別是弱網(wǎng)環(huán)境下。
QUIC 協(xié)議性能有多好?
Chromium ( Google 的 Chrome 瀏覽器背后的引擎)團(tuán)隊(duì)表示,其發(fā)現(xiàn) QUIC 的性能優(yōu)勢(shì)特別高,使得 Google 搜索延遲減少了 2% 以上,YouTube 的重新緩沖時(shí)間減少了 9% 以上,PC 客戶端吞吐量增加了 3% 以上,移動(dòng)設(shè)備的客戶端吞吐量增加了 7% 以上。
手機(jī)端我沒研究過怎么使用 QUIC 協(xié)議看 B 站視頻,但是谷歌瀏覽器則很容易搞定。
谷歌瀏覽器支持 QUIC 協(xié)議,這個(gè)是屬于實(shí)驗(yàn)性功能,QUIC 協(xié)議實(shí)際上還在草案中,還沒有正式發(fā)布,所以不是默認(rèn)啟動(dòng)的,需要手動(dòng)打開。
第一步,打開Chrome瀏覽器, 在地址輸入 chrome://flags/#enable-quic
, 將標(biāo)志設(shè)置為 Enabled
。
第二步,重啟瀏覽器后, 打開B站, 隨便點(diǎn)開個(gè)視頻,然后檢查是否使用 QUIC 協(xié)議進(jìn)行視頻播放, 檢查方法如下:
按下 F12
進(jìn)入瀏覽器調(diào)試信息界面;
選取 Network->Protocol, 如果 Protocol 顯示 h3 則表示目前是使用 HTTP/3 (意味著使用 QUIC 協(xié)議)協(xié)議進(jìn)行視頻內(nèi)容傳輸。
比如下圖,我在看何同學(xué)采訪庫克的B站視頻,使用了 HTTP3 協(xié)議:
好了,B 站的事情就介紹到這了,你以為這次我要聊 B 站,其實(shí)我要聊的是 HTTP/3 !
真不容易呀,小林為了讓大家學(xué)習(xí) HTTP/3,煞費(fèi)苦心布置了 B 站這個(gè)幌子,吸引大家點(diǎn)進(jìn)來。所以,大家不要覺得是標(biāo)題黨哈。
事實(shí)上,HTTP/3 現(xiàn)在還沒正式推出,不過自 2017 年起, HTTP/3 已經(jīng)更新到 34 個(gè)草案了,基本的特性已經(jīng)確定下來了,對(duì)于包格式可能后續(xù)會(huì)有變化。
所以,這次 HTTP/3 介紹不會(huì)涉及到包格式,只說它的特性。
HTTP/2 通過頭部壓縮、二進(jìn)制編碼、多路復(fù)用、服務(wù)器推送等新特性大幅度提升了 HTTP/1.1 的性能,而美中不足的是 HTTP/2 協(xié)議是基于 TCP 實(shí)現(xiàn)的,于是存在的缺陷有三個(gè)。
隊(duì)頭阻塞;
TCP 與 TLS 的握手時(shí)延遲;
網(wǎng)絡(luò)遷移需要重新連接;
HTTP/2 多個(gè)請(qǐng)求是跑在一個(gè) TCP 連接中的,那么當(dāng) TCP 丟包時(shí),整個(gè) TCP 都要等待重傳,那么就會(huì)阻塞該 TCP 連接中的所有請(qǐng)求。
因?yàn)?TCP 是字節(jié)流協(xié)議,TCP 層必須保證收到的字節(jié)數(shù)據(jù)是完整且有序的,如果序列號(hào)較低的 TCP 段在網(wǎng)絡(luò)傳輸中丟失了,即使序列號(hào)較高的 TCP 段已經(jīng)被接收了,應(yīng)用層也無法從內(nèi)核中讀取到這部分?jǐn)?shù)據(jù),從 HTTP 視角看,就是請(qǐng)求被阻塞了。
舉個(gè)例子,如下圖:
圖中發(fā)送方發(fā)送了很多個(gè) packet,每個(gè) packet 都有自己的序號(hào),你可以認(rèn)為是 TCP 的序列號(hào),其中 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 的隊(duì)頭阻塞問題,是在 TCP 層面發(fā)生的。
發(fā)起 HTTP 請(qǐng)求時(shí),需要經(jīng)過 TCP 三次握手和 TLS 四次握手(TLS 1.2)的過程,因此共需要 3 個(gè) RTT 的時(shí)延才能發(fā)出請(qǐng)求數(shù)據(jù)。
另外, TCP 由于具有「擁塞控制」的特性,所以剛建立連接的 TCP 會(huì)有個(gè)「慢啟動(dòng)」的過程,它會(huì)對(duì) TCP 連接產(chǎn)生'減速'效果。
一個(gè) TCP 連接是由四元組(源 IP 地址,源端口,目標(biāo) IP 地址,目標(biāo)端口)確定的,這意味著如果 IP 地址或者端口變動(dòng)了,就會(huì)導(dǎo)致需要 TCP 與 TLS 重新握手,這不利于移動(dòng)設(shè)備切換網(wǎng)絡(luò)的場(chǎng)景,比如 4G 網(wǎng)絡(luò)環(huán)境切換成 WIFI。
這些問題都是 TCP 協(xié)議固有的問題,無論應(yīng)用層的 HTTP/2 在怎么設(shè)計(jì)都無法逃脫。
要解決這個(gè)問題,就必須把傳輸層協(xié)議替換成 UDP,這個(gè)大膽的決定,HTTP/3 做了!
我們深知,UDP 是一個(gè)簡(jiǎn)單、不可靠的傳輸協(xié)議,而且是 UDP 包之間是無序的,也沒有依賴關(guān)系。
而且,UDP 是不需要連接的,也就不需要握手和揮手的過程,所以天然的就比 TCP 快。
當(dāng)然,HTTP/3 不僅僅只是簡(jiǎn)單將傳輸協(xié)議替換成了 UDP,還基于 UDP 協(xié)議在「應(yīng)用層」實(shí)現(xiàn)了 QUIC 協(xié)議,它具有類似 TCP 的連接管理、擁塞窗口、流量控制的網(wǎng)絡(luò)特性,相當(dāng)于將不可靠傳輸?shù)?UDP 協(xié)議變成“可靠”的了,所以不用擔(dān)心數(shù)據(jù)包丟失的問題。
QUIC 協(xié)議的優(yōu)點(diǎn)有很多,這里舉例幾個(gè),比如:
無隊(duì)頭阻塞;
更快的連接建立;
連接遷移;
QUIC 協(xié)議也有類似 HTTP/2 Stream 與多路復(fù)用的概念,也是可以在同一條連接上并發(fā)傳輸多個(gè) Stream,Stream 可以認(rèn)為就是一條 HTTP 請(qǐng)求。
由于 QUIC 使用的傳輸協(xié)議是 UDP,UDP 不關(guān)心數(shù)據(jù)包的順序,如果數(shù)據(jù)包丟失,UDP 也不關(guān)心。不過,QUIC 協(xié)議會(huì)保證數(shù)據(jù)包的可靠性,每個(gè)數(shù)據(jù)包都有一個(gè)序號(hào)唯一標(biāo)識(shí)。
如果 QUIC 連接中的某個(gè)流中的一個(gè)數(shù)據(jù)包丟失了,只會(huì)阻塞該流,其他流不會(huì)受影響。這與 HTTP/2 不同,HTTP/2 只要某個(gè)流中的數(shù)據(jù)包丟失了,其他流也會(huì)因此受影響。
所以,QUIC 連接上的多個(gè) Stream 之間并沒有依賴,都是獨(dú)立的,某個(gè)流發(fā)生丟包了,只會(huì)影響該流,其他流不受影響,消除了 HTTP/2 的隊(duì)頭阻塞問題。
對(duì)于 HTTP/1 和 HTTP/2 協(xié)議,TCP 和 TLS 是分層的,分別屬于內(nèi)核實(shí)現(xiàn)的傳輸層、openssl 庫實(shí)現(xiàn)的表示層,因此它們難以合并在一起,需要分批次來握手,先 TCP 握手,再 TLS 握手。
HTTP/3 在傳輸數(shù)據(jù)前雖然需要 QUIC 協(xié)議握手,這個(gè)握手過程只需要 1 RTT,握手的目的是為確認(rèn)雙方的「連接 ID」,連接遷移就是基于連接 ID 實(shí)現(xiàn)的。
但是 HTTP/3 的 QUIC 協(xié)議并不是與 TLS 分層,而是QUIC 內(nèi)部包含了 TLS,它在自己的幀會(huì)攜帶 TLS 里的“記錄”,再加上 QUIC 使用的是 TLS1.3,因此僅需 1 個(gè) RTT 就可以「同時(shí)」完成建立連接與密鑰協(xié)商,甚至在第二次連接的時(shí)候,應(yīng)用數(shù)據(jù)包可以和 QUIC 握手信息(連接信息 + TLS 信息)一起發(fā)送,達(dá)到 0-RTT 的效果。
如下圖右邊部分,HTTP/3 當(dāng)會(huì)話恢復(fù)時(shí),有效負(fù)載數(shù)據(jù)與第一個(gè)數(shù)據(jù)包一起發(fā)送,可以做到 0-RTT:
在前面我們提到,基于 TCP 傳輸協(xié)議的 HTTP 協(xié)議,由于是通過四元組(源 IP、源端口、目的 IP、目的端口)確定一條 TCP 連接。
那么當(dāng)移動(dòng)設(shè)備的網(wǎng)絡(luò)從 4G 切換到 WIFI 時(shí),意味著 IP 地址變化了,就必須要斷開連接,然后重新建立連接,而建立連接的過程包含 TCP 三次握手和 TLS 四次握手的時(shí)延,以及 TCP 慢啟動(dòng)的減速過程,給用戶的感覺就是網(wǎng)絡(luò)突然卡頓了一下,因此連接的遷移成本是很高的。
而 QUIC 協(xié)議沒有用四元組的方式來“綁定”連接,而是通過連接 ID來標(biāo)記通信的兩個(gè)端點(diǎn),客戶端和服務(wù)器可以各自選擇一組 ID 來標(biāo)記自己。
因此,即使移動(dòng)設(shè)備的網(wǎng)絡(luò)變化后,導(dǎo)致 IP 地址變化了,只要仍保有上下文信息(比如連接 ID、TLS 密鑰等),就可以“無縫”地復(fù)用原連接,消除重連的成本,沒有絲毫卡頓感,達(dá)到了連接遷移的功能。
了解完 QUIC 協(xié)議的特點(diǎn)后,我們?cè)賮砜纯?HTTP/3 協(xié)議在 HTTP 這一層做了什么變化。
HTTP/3 同 HTTP/2 一樣采用二進(jìn)制幀的結(jié)構(gòu),不同的地方在于 HTTP/2 的二進(jìn)制幀里需要定義 Stream,而 HTTP/3 自身不需要再定義 Stream,直接使用 QUIC 里的 Stream,于是 HTTP/3 的幀的結(jié)構(gòu)也變簡(jiǎn)單了。
從上圖可以看到,HTTP/3 幀頭只有兩個(gè)字段:類型和長度。
根據(jù)幀類型的不同,大體上分為數(shù)據(jù)幀和控制幀兩大類,HEADERS 幀(HTTP 頭部)和 DATA 幀(HTTP 包體)屬于數(shù)據(jù)幀。
HTTP/3 在頭部壓縮算法這一方便也做了升級(jí),升級(jí)成了 QPACK。與 HTTP/2 中的 HPACK 編碼方式相似,HTTP/3 中的 QPACK 也采用了靜態(tài)表、動(dòng)態(tài)表及 Huffman 編碼。
對(duì)于靜態(tài)表的變化,HTTP/2 中的 HPACK 的靜態(tài)表只有 61 項(xiàng),而 HTTP/3 中的 QPACK 的靜態(tài)表擴(kuò)大到 91 項(xiàng)。
HTTP/2 和 HTTP/3 的 Huffman 編碼并沒有多大不同,但是動(dòng)態(tài)表編解碼方式不同。
所謂的動(dòng)態(tài)表,在首次請(qǐng)求-響應(yīng)后,雙方會(huì)將未包含在靜態(tài)表中的 Header 項(xiàng)更新各自的動(dòng)態(tài)表,接著后續(xù)傳輸時(shí)僅用 1 個(gè)數(shù)字表示,然后對(duì)方可以根據(jù)這 1 個(gè)數(shù)字從動(dòng)態(tài)表查到對(duì)應(yīng)的數(shù)據(jù),就不必每次都傳輸長長的數(shù)據(jù),大大提升了編碼效率。
可以看到,動(dòng)態(tài)表是具有時(shí)序性的,如果首次出現(xiàn)的請(qǐng)求發(fā)生了丟包,后續(xù)的收到請(qǐng)求,對(duì)方就無法解碼出 HPACK 頭部,因?yàn)閷?duì)方還沒建立好動(dòng)態(tài)表,因此后續(xù)的請(qǐng)求解碼會(huì)阻塞到首次請(qǐng)求中丟失的數(shù)據(jù)包重傳過來。
HTTP/3 的 QPACK 解決了這一問題,那它是如何解決的呢?
QUIC 會(huì)有兩個(gè)特殊的單向流,所謂的單項(xiàng)流只有一端可以發(fā)送消息,雙向則指兩端都可以發(fā)送消息,傳輸 HTTP 消息時(shí)用的是雙向流,這兩個(gè)單向流的用法:
一個(gè)叫 QPACK Encoder Stream, 用于將一個(gè)字典(key-value)傳遞給對(duì)方,比如面對(duì)不屬于靜態(tài)表的 HTTP 請(qǐng)求頭部,客戶端可以通過這個(gè) Stream 發(fā)送字典;
一個(gè)叫 QPACK Decoder Stream,用于響應(yīng)對(duì)方,告訴它剛發(fā)的字典已經(jīng)更新到自己的本地動(dòng)態(tài)表了,后續(xù)就可以使用這個(gè)字典來編碼了。
這兩個(gè)特殊的單向流是用來同步雙方的動(dòng)態(tài)表,編碼方收到解碼方更新確認(rèn)的通知后,才使用動(dòng)態(tài)表編碼 HTTP 頭部。
HTTP/2 雖然具有多個(gè)流并發(fā)傳輸?shù)哪芰?,但是傳輸層?TCP 協(xié)議,于是存在以下缺陷:
隊(duì)頭阻塞,HTTP/2 多個(gè)請(qǐng)求跑在一個(gè) TCP 連接中,如果序列號(hào)較低的 TCP 段在網(wǎng)絡(luò)傳輸中丟失了,即使序列號(hào)較高的 TCP 段已經(jīng)被接收了,應(yīng)用層也無法從內(nèi)核中讀取到這部分?jǐn)?shù)據(jù),從 HTTP 視角看,就是多個(gè)請(qǐng)求被阻塞了;
TCP 和 TLS 握手時(shí)延,TCL 三次握手和 TLS 四次握手,共有 3-RTT 的時(shí)延;
連接遷移需要重新連接,移動(dòng)設(shè)備從 4G 網(wǎng)絡(luò)環(huán)境切換到 WIFI 時(shí),由于 TCP 是基于四元組來確認(rèn)一條 TCP 連接的,那么網(wǎng)絡(luò)環(huán)境變化后,就會(huì)導(dǎo)致 IP 地址或端口變化,于是 TCP 只能斷開連接,然后再重新建立連接,切換網(wǎng)絡(luò)環(huán)境的成本高;
HTTP/3 就將傳輸層從 TCP 替換成了 UDP,并在 UDP 協(xié)議上開發(fā)了 QUIC 協(xié)議,來保證數(shù)據(jù)的可靠傳輸。
QUIC 協(xié)議的特點(diǎn):
無隊(duì)頭阻塞,QUIC 連接上的多個(gè) Stream 之間并沒有依賴,都是獨(dú)立的,也不會(huì)有底層協(xié)議限制,某個(gè)流發(fā)生丟包了,只會(huì)影響該流,其他流不受影響;
建立連接速度快,因?yàn)?QUIC 內(nèi)部包含 TLS1.3,因此僅需 1 個(gè) RTT 就可以「同時(shí)」完成建立連接與 TLS 密鑰協(xié)商,甚至在第二次連接的時(shí)候,應(yīng)用數(shù)據(jù)包可以和 QUIC 握手信息(連接信息 + TLS 信息)一起發(fā)送,達(dá)到 0-RTT 的效果。
連接遷移,QUIC 協(xié)議沒有用四元組的方式來“綁定”連接,而是通過連接 ID 來標(biāo)記通信的兩個(gè)端點(diǎn),客戶端和服務(wù)器可以各自選擇一組 ID 來標(biāo)記自己,因此即使移動(dòng)設(shè)備的網(wǎng)絡(luò)變化后,導(dǎo)致 IP 地址變化了,只要仍保有上下文信息(比如連接 ID、TLS 密鑰等),就可以“無縫”地復(fù)用原連接,消除重連的成本;
另外 HTTP/3 的 QPACK 通過兩個(gè)特殊的單向流來同步雙方的動(dòng)態(tài)表,解決了 HTTP/2 的 HPACK 隊(duì)頭阻塞問題。
不過,由于 QUIC 使用的是 UDP 傳輸協(xié)議,UDP 屬于“二等公民”,大部分路由器在網(wǎng)絡(luò)繁忙的時(shí)候,會(huì)丟掉 UDP包,把“空間”讓給 TCP 包,所以 QUIC 的推廣之路應(yīng)該沒那么簡(jiǎn)單。
期待,HTTP/3 正式推出的那一天!
https://medium.com/faun/http-2-spdy-and-http-3-quic-bae7d9a3d484
https://developers.google.com/web/fundamentals/performance/http2?hl=zh-cn
https://blog.cloudflare.com/http3-the-past-present-and-future/
https://tools.ietf.org/html/draft-ietf-quic-http-34
https://tools.ietf.org/html/draft-ietf-quic-transport-34#section-17
https://ably.com/topic/http3?amp%3Butm_campaign=evergreen&%3Butm_source=reddit&utm_medium=referral
https://www.nginx.org.cn/article/detail/422
https://www.bilibili.com/read/cv793000/
https://www.chinaz.com/2020/1009/1192436.shtml
聯(lián)系客服