你是否也有這樣的困擾:打開 APP 巨耗時(shí)、刷劇一直在緩沖、追熱搜打不開頁面、信號稍微差點(diǎn)就直接加載失敗……
如果有一個(gè)協(xié)議能讓你的上網(wǎng)速度,在不需要任何修改的情況下就能提升 20%,特別是網(wǎng)絡(luò)差的環(huán)境下能夠提升 30% 以上;如果有一個(gè)協(xié)議可以讓你在 WiFi 和蜂窩數(shù)據(jù)切換時(shí),網(wǎng)絡(luò)完全不斷開、直播不卡頓、視頻不緩沖;你愿意去了解一下它嗎?它就是 QUIC 協(xié)議。本文將從 QUIC 的背景、原理、實(shí)踐部署等方面來詳細(xì)介紹。
網(wǎng)絡(luò)協(xié)議棧 1.1 什么叫網(wǎng)絡(luò)協(xié)議?
類似于我們生活中簽署的合同一樣,比如買賣合同是為了約束買賣雙方的行為按照合同的要求履行,網(wǎng)絡(luò)協(xié)議是為了約束網(wǎng)絡(luò)通信過程中各方(客戶端、服務(wù)端及中間設(shè)備)必須按照協(xié)議的規(guī)定進(jìn)行通信,它制定了數(shù)據(jù)包的格式、數(shù)據(jù)交互的過程等等,網(wǎng)絡(luò)中的所有設(shè)備都必須嚴(yán)格遵守才可以全網(wǎng)互聯(lián)。
在網(wǎng)絡(luò)協(xié)議棧中,是有分層的,每一層負(fù)責(zé)不同的事務(wù)。我們討論最多的有三個(gè):應(yīng)用層、傳輸層、網(wǎng)絡(luò)層。應(yīng)用層主要是針對應(yīng)用軟件進(jìn)行約束,比如你訪問網(wǎng)站需要按照 HTTP 協(xié)議格式和要求進(jìn)行,你發(fā)送電子郵件需要遵守 SMTP 等郵件協(xié)議的格式和要求;傳輸層主要負(fù)責(zé)數(shù)據(jù)包在網(wǎng)絡(luò)中的傳輸問題,比如如何保證數(shù)據(jù)傳輸?shù)臅r(shí)候的安全性和可靠性、數(shù)據(jù)包丟了怎么處理;網(wǎng)絡(luò)層,也叫路由轉(zhuǎn)發(fā)層,主要負(fù)責(zé)數(shù)據(jù)包從出發(fā)地到目的地,應(yīng)該怎樣選擇路徑才能更快的到達(dá)。合理的網(wǎng)絡(luò)協(xié)議能夠讓用戶上網(wǎng)更快!
1.2 HTTP/3 協(xié)議
HTTP/3 是第三個(gè)主要版本的 HTTP 協(xié)議。與其前任 HTTP/1.1 和 HTTP/2 不同,在 HTTP/3 中,棄用 TCP 協(xié)議,改為使用基于 UDP 協(xié)議的 QUIC 協(xié)議實(shí)現(xiàn)。所以,HTTP/3 的核心在于 QUIC 協(xié)議。顯然,HTTP/3 屬于應(yīng)用層協(xié)議,而它使用的 QUIC 協(xié)議屬于傳輸層協(xié)議。
1.3 我們需要 HTTP/3 協(xié)議嗎
很多人可能都會有這樣一個(gè)疑問,為什么在 2015 年才標(biāo)準(zhǔn)化了 HTTP/2 ,這么快就需要 HTTP/3?
我們知道,HTTP/2 通過引入“流”的概念,實(shí)現(xiàn)了多路復(fù)用。簡單來說,假設(shè)你訪問某個(gè)網(wǎng)站需要請求 10 個(gè)資源,你使用 HTTP1.1 協(xié)議只能串行地發(fā)請求,資源 1 請求成功之后才能發(fā)送資源 2 的請求,以此類推,這個(gè)過程是非常耗時(shí)的。如果想 10 個(gè)請求并發(fā),不需要串行等待的話,在 HTTP1.1 中,應(yīng)用就需要為一個(gè)域名同時(shí)建立 10 個(gè) TCP 連接才行(一般瀏覽器不允許建立這么多),這無疑是對資源的極大的浪費(fèi)。HTTP/2 的多路復(fù)用解決了這一問題,能使多條請求并發(fā)。
但現(xiàn)實(shí)很殘酷,為什么很多業(yè)務(wù)用了 HTTP/2,反倒不如 HTTP1.1 呢?
第一:多流并發(fā)帶來了請求優(yōu)先級的問題,因?yàn)橛械恼埱罂蛻舳耍ū热鐬g覽器)希望它能盡快返回,有的請求可以晚點(diǎn)返回;又或者有的請求需要依賴別的請求的資源來展示。流的優(yōu)先級表示了這個(gè)請求被處理的優(yōu)先級,比如客戶端請求的關(guān)鍵的 CSS 和 JS 資源是必須高優(yōu)先級返回的,圖片視頻等資源可以晚一點(diǎn)響應(yīng)。流的優(yōu)先級的設(shè)置是一個(gè)難以平衡或者難以做到公平合理的事情,如果設(shè)置稍微不恰當(dāng),就會導(dǎo)致有些請求很慢,這在用戶看來,就是用了 HTTP/2 之后,怎么有的請求變慢了。
第二:HTTP/2 解決了 HTTP 協(xié)議層面的隊(duì)頭阻塞,但是 TCP 的隊(duì)頭阻塞仍然沒有解決,所有的流都在一條 TCP 連接上,如果萬一序號小的某個(gè)包丟了,那么 TCP 為了保證到達(dá)的有序性,必須等這個(gè)包到達(dá)后才能滑動窗口,即使后面的序號大的包已經(jīng)到達(dá)了也不能被應(yīng)用程序讀取。這就導(dǎo)致了在多條流并發(fā)的時(shí)候,某條流的某個(gè)包丟了,序號在該包后面的其他流的數(shù)據(jù)都不能被應(yīng)用程序讀取。這種情況下如果換做 HTTP1.1,由于 HTTP1.1 是多條連接,某個(gè)連接上的請求丟包了,并不影響其他連接。所以在丟包比較嚴(yán)重的情況下,HTTP/2 整體效果大概率不如 HTTP1.1
事實(shí)上,我們并不是真的需要新的 HTTP 版本,而是需要對底層傳輸控制協(xié)議 (TCP) 進(jìn)行升級。
1.4 QUIC 協(xié)議棧

圖 0-QUIC 協(xié)議棧
QUIC 協(xié)議實(shí)現(xiàn)在用戶態(tài),建立在內(nèi)核態(tài)的 UDP 的基礎(chǔ)之上,集成了 TCP 的可靠傳輸特性,集成了 TLS1.3 協(xié)議,保證了用戶數(shù)據(jù)傳輸?shù)陌踩?/p>
QUIC 協(xié)議的優(yōu)秀特性 2.1 建連快
數(shù)據(jù)的發(fā)送和接收,要想保證安全和可靠,一定是需要連接的。TCP 需要,QUIC 也同樣需要。連接到底是什么?連接是一個(gè)通道,是在一個(gè)客戶端和一個(gè)服務(wù)端之間的唯一一條可信的通道,主要是為了安全考慮,建立了連接,也就是建立了可信通道,服務(wù)器對這個(gè)客戶端“很放心”,對于服務(wù)器來說:你想跟我進(jìn)行通信,得先讓我認(rèn)識一下你,我得先確認(rèn)一下你是好人,是有資格跟我通信的。那么這個(gè)確認(rèn)對方身份的過程,就是建立連接的過程。
傳統(tǒng)基于 TCP 的 HTTPS 的建連過程為什么如此慢?它需要 TCP 和 TLS 兩個(gè)建連過程。如圖 1 所示(傳統(tǒng) HTTPS 請求流程圖):

圖 1- 傳統(tǒng) HTTPS 請求流程圖
對于一個(gè)小請求(用戶數(shù)據(jù)量較?。┒裕瑐鬏敂?shù)據(jù)只需要 1 個(gè) RTT,但是光建連就花掉了 3 個(gè) RTT,這是非常不劃算的,這里建連包括兩個(gè)過程:TCP 建連需要 1 個(gè) RTT,TLS 建連需要 2 個(gè) RTT。RTT:Round Trip Time,數(shù)據(jù)包在網(wǎng)絡(luò)上一個(gè)來回的時(shí)間。
為什么需要兩個(gè)過程?可惡就可惡在這個(gè)地方,TCP 和 TLS 沒辦法合并,因?yàn)?TCP 是在內(nèi)核里完成的,TLS 是在用戶態(tài)。也許有人會說把干掉內(nèi)核里的 TCP,把 TCP 挪出來放到用戶態(tài),然后就可以和 TLS 一起處理了。首先,你干不掉內(nèi)核里的 TCP,TCP 太古老了,全世界的服務(wù)器的 TCP 都固化在內(nèi)核里了。所以,既然干不掉 TCP,那我不用它了,我再自創(chuàng)一個(gè)傳輸層協(xié)議,放到用戶態(tài),然后再結(jié)合 TLS,這樣不就可以把兩個(gè)建連過程合二為一了嗎?是的,這就是 QUIC。
2.1.1 QUIC 的 1-RTT 建連
如圖 2 所示,是 QUIC 的連接建立過程:初次建連只需要 1 個(gè) RTT 即可完成建連。后續(xù)再次建連就可以使用 0-RTT 特性

圖 2-QUIC 建連過程圖
QUIC 的 1-RTT 建連:客戶端與服務(wù)端初次建連(之前從未進(jìn)行通信過),或者長時(shí)間沒有通信過(0-RTT 過期了),只能進(jìn)行 1-RTT 建連。只有先進(jìn)行一次完整的 1-RTT 建連,后續(xù)一段時(shí)間內(nèi)的通信才可以進(jìn)行 0-RTT 建連。
如圖 3 所示:QUIC 的 1-RTT 建連可以分成兩個(gè)部分。QUIC 連接信息部分和 TLS1.3 握手部分。

圖 3-QUIC 建連抓包
QUIC 連接:協(xié)商 QUIC 版本號、協(xié)商 quic 傳輸參數(shù)、生成連接 ID、確定 Packet Number 等信息,類似于 TCP 的 SYN 報(bào)文;保證通信的兩端確認(rèn)過彼此,是對的人。
TLS1.3 握手:標(biāo)準(zhǔn)協(xié)議,非對稱加密,目的是為了協(xié)商出 對稱密鑰,然后后續(xù)傳輸?shù)臄?shù)據(jù)使用這個(gè)對稱密鑰進(jìn)行加密和解密,保護(hù)數(shù)據(jù)不被竊取。
我們重點(diǎn)看 QUIC 的 TLS1.3 握手過程。

圖 4-QUIC 的 1-RTT 握手流程
我們通過圖 4 可以看到,整個(gè)握手過程需要 2 次握手(第三次握手是帶了數(shù)據(jù)的),所以整個(gè)握手過程只需要 1-RTT(RTT 是指數(shù)據(jù)包在網(wǎng)絡(luò)上的一個(gè)來回)的時(shí)間。
1-RTT 的握手主要包含兩個(gè)過程:
客戶端發(fā)送 Client Hello 給服務(wù)端;
服務(wù)端回復(fù) Server Hello 給客戶端;
我們通過下圖中圖 5 和圖 6 來看 Client Hello 和 Server Hello 具體都做了啥:
第一次握手(Client Hello 報(bào)文)

圖 5-Client Hello 報(bào)文
首先,Client Hello 在擴(kuò)展字段里標(biāo)明了支持的 TLS 版本(Supported Version:TLS1.3)。值得注意的是 Version 字段必須要是 TLS1.2,這是因?yàn)?TLS1.2 已經(jīng)在互聯(lián)網(wǎng)上存在了 10 年。網(wǎng)絡(luò)中大量的網(wǎng)絡(luò)中間設(shè)備都十分老舊,這些網(wǎng)絡(luò)設(shè)備會識別中間的 TLS 握手頭部,所以 TLS1.3 的出現(xiàn)如果引入了未知的 TLS Version 必然會存在大量的握手失敗。

圖 6-Client Hello 報(bào)文
其次,ClientHello 中包含了非常重要的 key_share 擴(kuò)展:客戶端在發(fā)送之前,會自己根據(jù) DHE 算法生成一個(gè)公私鑰對。發(fā)送 Client Hello 報(bào)文的時(shí)候會把這個(gè)公鑰發(fā)過去,那么這個(gè)公鑰就存在于 key_share 中,key_share 還包含了客戶端所選擇的曲線 X25519??傊琸ey_share 是客戶端提前生成好的公鑰信息。
最后,Client Hello 里還包括了:客戶端支持的算法套、客戶端所支持的橢圓曲線以及簽名算法、psk 的模式等等,一起發(fā)給服務(wù)端。

圖 7-Client Hello 報(bào)文
第二次握手:(Server Hello 報(bào)文)

圖 8-Server Hello 報(bào)文
服務(wù)端自己根據(jù) DHE 算法也生成了一個(gè)公私鑰對,同樣的,Key_share 擴(kuò)展信息中也包含了 服務(wù)端的公鑰信息。服務(wù)端通過 ServerHello 報(bào)文將這些信息發(fā)送給客戶端。
至此為止,雙方(客戶端服務(wù)端)都拿到了對方的公鑰信息,然后結(jié)合自己的私鑰信息,生成 pre-master key,在這里官方的叫法是(client_handshake_traffic_secret 和server_handshake_traffic_secret),然后根據(jù)以下算法進(jìn)行算出 key 和 iv,使用 key 和 iv 對 Server Hello 之后所有的握手消息進(jìn)行加密。
注意:在握手完成之后,服務(wù)端會發(fā)送一個(gè) New Session Ticket 報(bào)文給客戶端,這個(gè)包非常重要,這是 0-RTT 實(shí)現(xiàn)的基礎(chǔ)。

圖 9-New Session Ticket 報(bào)文
2.1.2 QUIC 的 0-RTT 握手
這個(gè)功能類似于 TLS1.2 的會話復(fù)用,或者說 0-RTT 是基于會話復(fù)用功能的。

圖 10- QUIC 的 0-RTT 流程圖
通過上面圖 10 我們可以看到,client 和 server 在建連時(shí),仍然需要兩次握手,仍然需要 1 個(gè) rtt,但是為什么我們說這是 0-rtt 呢,是因?yàn)?client 在發(fā)送第一個(gè)包 client hello 時(shí),就帶上了數(shù)據(jù)(HTTP 請求),從什么時(shí)候開始發(fā)送數(shù)據(jù)這個(gè)角度上來看,的確是 0-RTT。
我們通過抓包來看 0-RTT 的過程:

圖 11- QUIC 的 0-RTT 抓包
所以真正在實(shí)現(xiàn) 0-RTT 的時(shí)候,請求的數(shù)據(jù)并不會跟 Initial 報(bào)文(內(nèi)含 Client Hello)一起發(fā)送,而是單獨(dú)一個(gè)數(shù)據(jù)包(0-RTT 包)進(jìn)行發(fā)送,只不過是跟 Initial 包同時(shí)進(jìn)行發(fā)送而已。

圖 12- QUIC 的 0-RTT 包
我們單獨(dú)看 Initial 報(bào)文發(fā)現(xiàn),除了 pre_share_key、early-data 標(biāo)識等信息與 1-RTT 時(shí)不同,其他并無區(qū)別。
2.1.3 QUIC 建連需要注意的問題
第一,QUIC 實(shí)現(xiàn)的時(shí)候,必須緩存收到的亂序加密幀,這個(gè)緩存至少要大于 4096 字節(jié)。當(dāng)然可以選擇緩存更多的數(shù)據(jù),更大的緩存上限意味著可以交換更大的密鑰或證書。終端的緩存區(qū)大小不必在整個(gè)連接生命周期內(nèi)保持不變。這里記?。簛y序幀一定要緩存下來。如果不緩存,會導(dǎo)致連接失敗。如果終端的緩存區(qū)不夠用了,則其可以通過暫時(shí)擴(kuò)大緩存空間確保握手完成。如果終端不擴(kuò)大其緩存,則其必須以錯(cuò)誤碼 CRYPTO_BUFFER_EXCEEDED 關(guān)閉連接。
第二,0-RTT 存在前向安全問題,請慎用!
2.2 連接遷移
QUIC 通過連接 ID 實(shí)現(xiàn)了連接遷移。
我們經(jīng)常需要在 WiFi 和 4G 之間進(jìn)行切換,比如我們在家里時(shí)使用 WiFi,出門在路上,切換到 4G 或 5G,到了商場,又連上了商場的 WiFi,到了餐廳,又切換到了餐廳的 WiFi,所以我們的日常生活中需要經(jīng)常性的切換網(wǎng)絡(luò),那每一次的切換網(wǎng)絡(luò),都將導(dǎo)致我們的 IP 地址發(fā)生變化。
傳統(tǒng)的 TCP 協(xié)議是以四元組(源 IP 地址、源端口號、目的 ID 地址、目的端口號)來標(biāo)識一條連接,那么一旦四元組的任何一個(gè)元素發(fā)生了改變,這條連接就會斷掉,那么這條連接中正在傳輸?shù)臄?shù)據(jù)就會斷掉,切換到新的網(wǎng)絡(luò)后可能需要重新去建立連接,然后重新發(fā)送數(shù)據(jù)。這將會導(dǎo)致用戶的網(wǎng)絡(luò)會“卡”一下。
但是,QUIC 不再以四元組作為唯一標(biāo)識,QUIC 使用連接 ID 來標(biāo)識一條連接,無論你的網(wǎng)絡(luò)如何切換,只要連接 ID 不變,那么這條連接就不會斷,這就叫連接遷移!

圖 13-QUIC 連接遷移介紹
2.2.1 連接 ID
每條連接擁有一組連接標(biāo)識符,也就是連接 ID,每個(gè)連接 ID 都能標(biāo)識這條連接。連接 ID 是由一端獨(dú)立選擇的,每個(gè)端(客戶端和服務(wù)端統(tǒng)稱為端)選擇連接 ID 供對端使用。也就是說,客戶端生成的連接 ID 供服務(wù)端使用(服務(wù)端發(fā)送數(shù)據(jù)時(shí)使用客戶端生成的連接 ID 作為目的連接 ID),反過來一樣的。
連接 ID 的主要功能是確保底層協(xié)議(UDP、IP 及更底層的協(xié)議棧)發(fā)生地址變更(比如 IP 地址變了,或者端口號變了)時(shí)不會導(dǎo)致一個(gè) QUIC 連接的數(shù)據(jù)包被傳輸?shù)藉e(cuò)誤的 QUIC 終端(客戶端和服務(wù)端統(tǒng)稱為終端)上。
2.2.2 QUIC 的連接遷移過程
QUIC 限制連接遷移為僅客戶端可以發(fā)起,客戶端負(fù)責(zé)發(fā)起所有遷移。如果客戶端接收到了一個(gè)未知的服務(wù)器發(fā)來的數(shù)據(jù)包,那么客戶端必須丟棄這些數(shù)據(jù)包。
如圖 14 所示,連接遷移過程總共需要四個(gè)步驟。
連接遷移之前,客戶端使用 IP1 和服務(wù)端進(jìn)行通信;
客戶端 IP 變成 IP2,并且使用 IP2 發(fā)送非探測幀給服務(wù)端;
啟動路徑驗(yàn)證(雙方都需要互相驗(yàn)證),通過 PATH_CHANLLENGE 幀和 PATH_RESPONSE 幀進(jìn)行驗(yàn)證。
驗(yàn)證通過后,使用 IP2 進(jìn)行通信。

圖 14- 連接遷移流程圖
2.3 解決 TCP 隊(duì)頭阻塞問題
在 HTTP/2 中引入了流的概念。目的是實(shí)現(xiàn) 多個(gè)請求在同一個(gè)連接上并發(fā),從而提升網(wǎng)頁加載的效率。

圖 15-QUIC 解決 TCP 隊(duì)頭阻塞問題
由圖 15 來看,假設(shè)有兩個(gè)請求同時(shí)發(fā)送,紅色的是請求 1,藍(lán)色的是請求 2,這兩個(gè)請求在兩條不同的流中進(jìn)行傳輸。假設(shè)在傳輸過程中,請求 1 的某個(gè)數(shù)據(jù)包丟了,如果是 TCP,即使請求 2 的所有數(shù)據(jù)包都收到了,但是也只能阻塞在內(nèi)核緩沖區(qū)中,無法交給應(yīng)用層。但是 QUIC 就不一樣了,請求 1 的數(shù)據(jù)包丟了只會阻塞請求 1,請求 2 不會受到阻塞。
有些人不禁發(fā)問,不是說 HTTP2 也有流的概念嗎,為什么只有 QUIC 才能解決呢,這個(gè)根本原因就在于,HTTP2 的傳輸層用的 TCP,TCP 的實(shí)現(xiàn)是在內(nèi)核態(tài)的,而流是實(shí)現(xiàn)在用戶態(tài)度,TCP 是看不到“流”的,所以在 TCP 中,它不知道這個(gè)數(shù)據(jù)包是請求 1 還是請求 2 的,只會根據(jù) seq number 來判斷包的先后順序。
2.4 更優(yōu)的擁塞控制算法
擁塞控制算法中最重要的一個(gè)參數(shù)是 RTT,RTT 的準(zhǔn)確性決定了擁塞控制算法的準(zhǔn)確性;然而,TCP 的 RTT 測量往往不準(zhǔn)確,QUIC 的 RTT 測量是準(zhǔn)確的。

圖 16-TCP 計(jì)算 RTT
如圖 16 所示:由于網(wǎng)絡(luò)中經(jīng)常出現(xiàn)丟包,需要重傳,在 TCP 協(xié)議中,初始包和重傳包的序號是一樣的,擁塞控制算法進(jìn)行計(jì)算 RTT 的時(shí)候,無法區(qū)別是初始包還是重傳包,這將導(dǎo)致 RTT 的計(jì)算值要么偏大,要么偏小。

圖 17-QUIC 計(jì)算 RTT
如圖 17 所示:QUIC 通過 Packet Number 來標(biāo)識包的序號,而且規(guī)定 Packet Number 只能單調(diào)遞增,這也就解決了初始包和重傳包的二義性。從而保證 RTT 的值是準(zhǔn)確的。
另外,不同于 TCP,QUIC 的擁塞控制算法是可插拔的,由于其實(shí)現(xiàn)在用戶態(tài),服務(wù)可以根據(jù)不同的業(yè)務(wù),甚至不同的連接靈活選擇使用不同的擁塞控制算法。(Reno、New Reno、Cubic、BBR 等算法都有自己適合的場景)
2.5 QUIC 的兩級流量控制
很多人搞不清楚流量控制與擁塞控制的區(qū)別。二者有本質(zhì)上的區(qū)別。
流量控制要解決的問題是:接收方控制發(fā)送方的數(shù)據(jù)發(fā)送的速度,就是我的接收能力就那么大點(diǎn),你別發(fā)太快了,你發(fā)太快了我承受不住,會給你丟掉 你還得重新發(fā)。
擁塞控制要解決的問題是:數(shù)據(jù)在網(wǎng)絡(luò)的傳輸過程中,是否網(wǎng)絡(luò)有擁塞,是否有丟包,是否有亂序等問題。如果中間傳輸?shù)臅r(shí)候網(wǎng)絡(luò)特別卡,數(shù)據(jù)包丟在中間了,發(fā)送方就需要重傳,那么怎么判斷是否擁塞了,重傳要怎么重傳法,按照什么算法進(jìn)行發(fā)送數(shù)據(jù)才能盡可能避免數(shù)據(jù)包在中間路徑丟掉,這是擁塞控制的核心。
所以,流量控制解決的是接收方的接收能力問題,一般采用滑動窗口算法;擁塞控制要解決的是中間傳輸?shù)臅r(shí)候網(wǎng)絡(luò)是否擁堵的問題,一般采用慢啟動、擁塞避免、擁塞恢復(fù)、快速重傳等算法。

圖 18-QUIC 流量控制
QUIC 是雙級流控,不僅有連接這一個(gè)級別的流控,還有流這個(gè)級別的流控。如下圖所示,每個(gè)流都有自己的可用窗口,可用窗口的大小取決于最大窗口數(shù)減去發(fā)送出去的最大偏移數(shù),跟中間已經(jīng)發(fā)送出去的數(shù)據(jù)包,是否按順序收到了對端的 ACK 無關(guān)。
QUIC 協(xié)議如何優(yōu)化
QUIC 協(xié)議定義了很多優(yōu)秀的功能,但是在實(shí)現(xiàn)的過程中,我們會遇到很多問題導(dǎo)致無法達(dá)到預(yù)期的性能,比如 0-RTT 率很低,連接遷移失敗率很高等等。
3.1 QUIC 的 0-RTT 成功率不高
導(dǎo)致 0-RTT 成功率不高的原因一般有如下幾個(gè):
1. 服務(wù)端一般都是集群,對于客戶端來說,處理請求的服務(wù)端是不固定的,新的請求到來時(shí),如果當(dāng)前 client 沒有請求過該服務(wù)器,則服務(wù)器上沒有相關(guān)會話信息,會把該請求當(dāng)做一個(gè)新的連接來處理,重新走 1-RTT。
針對此種情況,我們可以考慮集群中所有的服務(wù)器使用相同的 ticket 文件。
2. 客戶端 IP 不是固定的,在發(fā)生連接遷移時(shí),服務(wù)端下發(fā)的 token 融合了客戶端的 IP,這個(gè) IP 變化了的話,攜帶 token 服務(wù)端校驗(yàn)不過,0-RTT 會失敗。
針對這個(gè)問題,我們可以考慮采用如圖 19 所示的方法,使用設(shè)備信息或者 APP 信息來生成 token,唯一標(biāo)識一個(gè)客戶端。

圖 19- 使用設(shè)備信息提高 0-RTT 的成功率
3. Session Ticket 過期時(shí)間默認(rèn)是 2 天,超過 2 天后就會導(dǎo)致 0-RTT 失敗,然后降級走 1-RTT??梢钥紤]增長過期時(shí)間。
3.2 實(shí)現(xiàn)連接遷移并不容易。
連接遷移的實(shí)現(xiàn),不可避開的兩個(gè)問題:一個(gè)是四層負(fù)載均衡器對連接遷移的影響,一個(gè)是七層負(fù)載均衡器對連接遷移的影響。
四層負(fù)載均衡器的影響:LVS、DPVS 等四層負(fù)載均衡工具基于四元組進(jìn)行轉(zhuǎn)發(fā),當(dāng)連接遷移發(fā)生時(shí),四元組會發(fā)生變化,該組件就會把同一個(gè)請求的數(shù)據(jù)包發(fā)送到不同的后端服務(wù)器上,導(dǎo)致連接遷移失??;
七層負(fù)載均衡器的影響(QUIC 服務(wù)器多核的影響):由于多核的影響,一般服務(wù)器會有多個(gè) QUIC 服務(wù)端進(jìn)程,每個(gè)進(jìn)程負(fù)載處理不同的連接。內(nèi)核收到數(shù)據(jù)包后,會根據(jù)二元組(源 IP、源 port)選擇已經(jīng)存在的連接,并把數(shù)據(jù)包交給對應(yīng)的 socket。在連接遷移發(fā)生時(shí),源地址發(fā)生改變,可能會讓接下來的數(shù)據(jù)包去到不同的進(jìn)程,影響 socket 數(shù)據(jù)的接收。
如何解決以上兩個(gè)問題?DPVS 要想支持 QUIC 的連接遷移,就不能再以四元組進(jìn)行轉(zhuǎn)發(fā),需要以連接 ID 進(jìn)行轉(zhuǎn)發(fā),需要建立 連接 ID 與對應(yīng)的后端服務(wù)器的對應(yīng)關(guān)系;
QUIC 服務(wù)器也是一樣的,內(nèi)核就不能用四元組來進(jìn)行查找 socket,四元組查找不到時(shí),就必須使用連接 ID 進(jìn)行查找 socket。但是內(nèi)核代碼又不能去修改(不可能去更新所有服務(wù)器的內(nèi)核版本),那么我們可以使用 eBPF 的方法進(jìn)行解決。如下圖 20 所示:

圖 20- 多核 QUIC 服務(wù)器解決連接遷移問題
3.3 UDP 被限速或禁閉
業(yè)內(nèi)統(tǒng)計(jì)數(shù)據(jù)全球有 7% 地區(qū)的運(yùn)營商對 UDP 有限速或者禁閉,除了運(yùn)營商還有很多企業(yè)、公共場合也會限制 UDP 流量甚至禁用 UDP。這對使用 UDP 來承載 QUIC 協(xié)議的場景會帶來致命的傷害。對此,我們可以采用多路競速的方式使用 TCP 和 QUIC 同時(shí)建連。除了在建連進(jìn)行競速以外,還可以對網(wǎng)絡(luò) QUIC 和 TCP 的傳輸延時(shí)進(jìn)行實(shí)時(shí)監(jiān)控和對比,如果有鏈路對 UDP 進(jìn)行了限速,可以動態(tài)從 QUIC 切換到 TCP。

圖 21-QUIC 和 TCP 協(xié)議競速
3.4 QUIC 對 CPU 消耗大
相對于 TCP,為什么 QUIC 更消耗資源?
QUIC 在用戶態(tài)實(shí)現(xiàn),需要更多的內(nèi)核空間與用戶空間的數(shù)據(jù)拷貝和上下文切換;
QUIC 的 ACK 報(bào)文也是加密的,TCP 是明文的。
內(nèi)核知道 TCP 連接的狀態(tài),不用為每一個(gè)數(shù)據(jù)包去做諸如查找目的路由、防火墻規(guī)則等操作,只需要在 tcp 連接建立的時(shí)候做一次即可,然而 QUIC 不行;
總的來說,QUIC 服務(wù)端消耗 CPU 的地方主要有三個(gè):密碼算法的開銷;udp 收發(fā)包的開銷;協(xié)議棧的開銷;
針對這些,我們可以適當(dāng)采取優(yōu)化措施來:
使用 Intel 硬件加速卡卸載 TLS 握手
開啟 GSO 功能。
數(shù)據(jù)在傳輸過程中,可以將一輪中所有的 ACK 解析后再同時(shí)進(jìn)行處理,避免處理大量的 ACK。
適當(dāng)將 QUIC 的包長限制調(diào)高(比如從默認(rèn)的 1200 調(diào)到 1400 個(gè)字節(jié))
減少協(xié)議棧的內(nèi)存拷貝
QUIC 的性能
從公開的數(shù)據(jù)來看,國內(nèi)各個(gè)廠(騰訊、阿里、字節(jié)、華為、OPPO、網(wǎng)易等等)使用了 QUIC 協(xié)議后,都有很大的提升,比如網(wǎng)易上了 QUIC 后,響應(yīng)速度提升 45%,請求錯(cuò)誤率降低 50%;比如字節(jié)火山引擎使用 QUIC 后,建連耗時(shí)降低 20%~30%;比如騰訊使用 QUIC 后,在騰訊會議、直播、游戲等場景耗時(shí)也降低 30%;

圖 22- 字節(jié)火山引擎 QUIC 業(yè)務(wù)收益
總 結(jié)
QUIC 協(xié)議的出現(xiàn),為 HTTP/3 奠定了基礎(chǔ)。這是近些年在 web 協(xié)議上最大的變革,也是最優(yōu)秀的一次實(shí)踐。面對新的協(xié)議,我們總是有著各種各樣的擔(dān)憂,誠然,QUIC 協(xié)議在穩(wěn)定性上在成熟度上,的確還不如 TCP 協(xié)議,但是經(jīng)過近幾年的發(fā)展,成熟度已經(jīng)相當(dāng)不錯(cuò)了,Nginx 近期也發(fā)布了 1.25.0 版本,支持了 QUIC 協(xié)議。所以面對這樣優(yōu)秀的協(xié)議,我們希望更多的公司,更多的業(yè)務(wù)參與進(jìn)來使用 QUIC,推動 QUIC 更好的發(fā)展,推動用戶上網(wǎng)速度更快!
-
網(wǎng)絡(luò)協(xié)議
+關(guān)注
關(guān)注
3文章
274瀏覽量
22505 -
HTTP
+關(guān)注
關(guān)注
0文章
531瀏覽量
34698 -
網(wǎng)絡(luò)通信
+關(guān)注
關(guān)注
4文章
829瀏覽量
32298 -
Quic
+關(guān)注
關(guān)注
0文章
25瀏覽量
7502
原文標(biāo)題:一文讀懂 QUIC 協(xié)議:更快、更穩(wěn)、更高效的網(wǎng)絡(luò)通信
文章出處:【微信號:AI前線,微信公眾號:AI前線】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
一文讀懂CAN XL協(xié)議
ESP32-C6 智能網(wǎng)關(guān)設(shè)備WiFi6高性能通信應(yīng)用
愛普生SG3225EEN低抖動差分晶振在網(wǎng)絡(luò)通信的應(yīng)用
智多晶LWIP網(wǎng)絡(luò)通信系統(tǒng)介紹
雷卯收集網(wǎng)絡(luò)通信開發(fā)板
傳感器網(wǎng)絡(luò)通信協(xié)議的核心技術(shù)要素
一文讀懂什么是「雷電4」

一文讀懂QUIC協(xié)議:更快、更穩(wěn)、更高效的網(wǎng)絡(luò)通信
評論