你是否也有這樣的困擾:打開 APP 巨耗時、刷劇一直在緩沖、追熱搜打不開頁面、信號稍微差點(diǎn)就直接加載失敗……
如果有一個協(xié)議能讓你的上網(wǎng)速度,在不需要任何修改的情況下就能提升 20%,特別是網(wǎng)絡(luò)差的環(huán)境下能夠提升 30% 以上;如果有一個協(xié)議可以讓你在 WiFi 和蜂窩數(shù)據(jù)切換時,網(wǎng)絡(luò)完全不斷開、直播不卡頓、視頻不緩沖;你愿意去了解一下它嗎?它就是 QUIC 協(xié)議。本文將從 QUIC 的背景、原理、實踐部署等方面來詳細(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ù)。我們討論最多的有三個:應(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ù)據(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 是第三個主要版本的 HTTP 協(xié)議。與其前任 HTTP/1.1 和 HTTP/2 不同,在 HTTP/3 中,棄用 TCP 協(xié)議,改為使用基于 UDP 協(xié)議的 QUIC 協(xié)議實現(xiàn)。所以,HTTP/3 的核心在于 QUIC 協(xié)議。顯然,HTTP/3 屬于應(yīng)用層協(xié)議,而它使用的 QUIC 協(xié)議屬于傳輸層協(xié)議。
1.3 我們需要 HTTP/3 協(xié)議嗎
很多人可能都會有這樣一個疑問,為什么在 2015 年才標(biāo)準(zhǔn)化了 HTTP/2 ,這么快就需要 HTTP/3?
我們知道,HTTP/2 通過引入“流”的概念,實現(xiàn)了多路復(fù)用。簡單來說,假設(shè)你訪問某個網(wǎng)站需要請求 10 個資源,你使用 HTTP1.1 協(xié)議只能串行地發(fā)請求,資源 1 請求成功之后才能發(fā)送資源 2 的請求,以此類推,這個過程是非常耗時的。如果想 10 個請求并發(fā),不需要串行等待的話,在 HTTP1.1 中,應(yīng)用就需要為一個域名同時建立 10 個 TCP 連接才行(一般瀏覽器不允許建立這么多),這無疑是對資源的極大的浪費(fèi)。HTTP/2 的多路復(fù)用解決了這一問題,能使多條請求并發(fā)。
但現(xiàn)實很殘酷,為什么很多業(yè)務(wù)用了 HTTP/2,反倒不如 HTTP1.1 呢?
第一:多流并發(fā)帶來了請求優(yōu)先級的問題,因為有的請求客戶端(比如瀏覽器)希望它能盡快返回,有的請求可以晚點(diǎn)返回;又或者有的請求需要依賴別的請求的資源來展示。流的優(yōu)先級表示了這個請求被處理的優(yōu)先級,比如客戶端請求的關(guān)鍵的 CSS 和 JS 資源是必須高優(yōu)先級返回的,圖片視頻等資源可以晚一點(diǎn)響應(yīng)。流的優(yōu)先級的設(shè)置是一個難以平衡或者難以做到公平合理的事情,如果設(shè)置稍微不恰當(dāng),就會導(dǎo)致有些請求很慢,這在用戶看來,就是用了 HTTP/2 之后,怎么有的請求變慢了。
第二:HTTP/2 解決了 HTTP 協(xié)議層面的隊頭阻塞,但是 TCP 的隊頭阻塞仍然沒有解決,所有的流都在一條 TCP 連接上,如果萬一序號小的某個包丟了,那么 TCP 為了保證到達(dá)的有序性,必須等這個包到達(dá)后才能滑動窗口,即使后面的序號大的包已經(jīng)到達(dá)了也不能被應(yīng)用程序讀取。這就導(dǎo)致了在多條流并發(fā)的時候,某條流的某個包丟了,序號在該包后面的其他流的數(shù)據(jù)都不能被應(yīng)用程序讀取。這種情況下如果換做 HTTP1.1,由于 HTTP1.1 是多條連接,某個連接上的請求丟包了,并不影響其他連接。所以在丟包比較嚴(yán)重的情況下,HTTP/2 整體效果大概率不如 HTTP1.1
事實上,我們并不是真的需要新的 HTTP 版本,而是需要對底層傳輸控制協(xié)議 (TCP) 進(jìn)行升級。
1.4 QUIC 協(xié)議棧
圖 0-QUIC 協(xié)議棧
QUIC 協(xié)議實現(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 也同樣需要。連接到底是什么?連接是一個通道,是在一個客戶端和一個服務(wù)端之間的唯一一條可信的通道,主要是為了安全考慮,建立了連接,也就是建立了可信通道,服務(wù)器對這個客戶端“很放心”,對于服務(wù)器來說:你想跟我進(jìn)行通信,得先讓我認(rèn)識一下你,我得先確認(rèn)一下你是好人,是有資格跟我通信的。那么這個確認(rèn)對方身份的過程,就是建立連接的過程。
傳統(tǒng)基于 TCP 的 HTTPS 的建連過程為什么如此慢?它需要 TCP 和 TLS 兩個建連過程。如圖 1 所示(傳統(tǒng) HTTPS 請求流程圖):
圖 1- 傳統(tǒng) HTTPS 請求流程圖
對于一個小請求(用戶數(shù)據(jù)量較小)而言,傳輸數(shù)據(jù)只需要 1 個 RTT,但是光建連就花掉了 3 個 RTT,這是非常不劃算的,這里建連包括兩個過程:TCP 建連需要 1 個 RTT,TLS 建連需要 2 個 RTT。RTT:Round Trip Time,數(shù)據(jù)包在網(wǎng)絡(luò)上一個來回的時間。
為什么需要兩個過程?可惡就可惡在這個地方,TCP 和 TLS 沒辦法合并,因為 TCP 是在內(nèi)核里完成的,TLS 是在用戶態(tài)。也許有人會說把干掉內(nèi)核里的 TCP,把 TCP 挪出來放到用戶態(tài),然后就可以和 TLS 一起處理了。首先,你干不掉內(nèi)核里的 TCP,TCP 太古老了,全世界的服務(wù)器的 TCP 都固化在內(nèi)核里了。所以,既然干不掉 TCP,那我不用它了,我再自創(chuàng)一個傳輸層協(xié)議,放到用戶態(tài),然后再結(jié)合 TLS,這樣不就可以把兩個建連過程合二為一了嗎?是的,這就是 QUIC。
2.1.1 QUIC 的 1-RTT 建連
如圖 2 所示,是 QUIC 的連接建立過程:初次建連只需要 1 個 RTT 即可完成建連。后續(xù)再次建連就可以使用 0-RTT 特性
圖 2-QUIC 建連過程圖
QUIC 的 1-RTT 建連:客戶端與服務(wù)端初次建連(之前從未進(jìn)行通信過),或者長時間沒有通信過(0-RTT 過期了),只能進(jìn)行 1-RTT 建連。只有先進(jìn)行一次完整的 1-RTT 建連,后續(xù)一段時間內(nèi)的通信才可以進(jìn)行 0-RTT 建連。
如圖 3 所示:QUIC 的 1-RTT 建連可以分成兩個部分。QUIC 連接信息部分和 TLS1.3 握手部分。
圖 3-QUIC 建連抓包
QUIC 連接:協(xié)商 QUIC 版本號、協(xié)商 quic 傳輸參數(shù)、生成連接 ID、確定 Packet Number 等信息,類似于 TCP 的 SYN 報文;保證通信的兩端確認(rèn)過彼此,是對的人。
TLS1.3 握手:標(biāo)準(zhǔn)協(xié)議,非對稱加密,目的是為了協(xié)商出 對稱密鑰,然后后續(xù)傳輸?shù)臄?shù)據(jù)使用這個對稱密鑰進(jìn)行加密和解密,保護(hù)數(shù)據(jù)不被竊取。
我們重點(diǎn)看 QUIC 的 TLS1.3 握手過程。
圖 4-QUIC 的 1-RTT 握手流程
我們通過圖 4 可以看到,整個握手過程需要 2 次握手(第三次握手是帶了數(shù)據(jù)的),所以整個握手過程只需要 1-RTT(RTT 是指數(shù)據(jù)包在網(wǎng)絡(luò)上的一個來回)的時間。
1-RTT 的握手主要包含兩個過程:
客戶端發(fā)送 Client Hello 給服務(wù)端;
服務(wù)端回復(fù) Server Hello 給客戶端;
我們通過下圖中圖 5 和圖 6 來看 Client Hello 和 Server Hello 具體都做了啥:
第一次握手(Client Hello 報文)
圖 5-Client Hello 報文
首先,Client Hello 在擴(kuò)展字段里標(biāo)明了支持的 TLS 版本(Supported Version:TLS1.3)。值得注意的是 Version 字段必須要是 TLS1.2,這是因為 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 報文
其次,ClientHello 中包含了非常重要的 key_share 擴(kuò)展:客戶端在發(fā)送之前,會自己根據(jù) DHE 算法生成一個公私鑰對。發(fā)送 Client Hello 報文的時候會把這個公鑰發(fā)過去,那么這個公鑰就存在于 key_share 中,key_share 還包含了客戶端所選擇的曲線 X25519。總之,key_share 是客戶端提前生成好的公鑰信息。
最后,Client Hello 里還包括了:客戶端支持的算法套、客戶端所支持的橢圓曲線以及簽名算法、psk 的模式等等,一起發(fā)給服務(wù)端。
圖 7-Client Hello 報文
第二次握手:(Server Hello 報文)
圖 8-Server Hello 報文
服務(wù)端自己根據(jù) DHE 算法也生成了一個公私鑰對,同樣的,Key_share 擴(kuò)展信息中也包含了 服務(wù)端的公鑰信息。服務(wù)端通過 ServerHello 報文將這些信息發(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ā)送一個 New Session Ticket 報文給客戶端,這個包非常重要,這是 0-RTT 實現(xiàn)的基礎(chǔ)。
圖 9-New Session Ticket 報文
2.1.2 QUIC 的 0-RTT 握手
這個功能類似于 TLS1.2 的會話復(fù)用,或者說 0-RTT 是基于會話復(fù)用功能的。
圖 10- QUIC 的 0-RTT 流程圖
通過上面圖 10 我們可以看到,client 和 server 在建連時,仍然需要兩次握手,仍然需要 1 個 rtt,但是為什么我們說這是 0-rtt 呢,是因為 client 在發(fā)送第一個包 client hello 時,就帶上了數(shù)據(jù)(HTTP 請求),從什么時候開始發(fā)送數(shù)據(jù)這個角度上來看,的確是 0-RTT。
我們通過抓包來看 0-RTT 的過程:
圖 11- QUIC 的 0-RTT 抓包
所以真正在實現(xiàn) 0-RTT 的時候,請求的數(shù)據(jù)并不會跟 Initial 報文(內(nèi)含 Client Hello)一起發(fā)送,而是單獨(dú)一個數(shù)據(jù)包(0-RTT 包)進(jìn)行發(fā)送,只不過是跟 Initial 包同時進(jìn)行發(fā)送而已。
圖 12- QUIC 的 0-RTT 包
我們單獨(dú)看 Initial 報文發(fā)現(xiàn),除了 pre_share_key、early-data 標(biāo)識等信息與 1-RTT 時不同,其他并無區(qū)別。
2.1.3 QUIC 建連需要注意的問題
第一,QUIC 實現(xiàn)的時候,必須緩存收到的亂序加密幀,這個緩存至少要大于 4096 字節(jié)。當(dāng)然可以選擇緩存更多的數(shù)據(jù),更大的緩存上限意味著可以交換更大的密鑰或證書。終端的緩存區(qū)大小不必在整個連接生命周期內(nèi)保持不變。這里記?。簛y序幀一定要緩存下來。如果不緩存,會導(dǎo)致連接失敗。如果終端的緩存區(qū)不夠用了,則其可以通過暫時擴(kuò)大緩存空間確保握手完成。如果終端不擴(kuò)大其緩存,則其必須以錯誤碼 CRYPTO_BUFFER_EXCEEDED 關(guān)閉連接。
第二,0-RTT 存在前向安全問題,請慎用!
2.2 連接遷移
QUIC 通過連接 ID 實現(xiàn)了連接遷移。
我們經(jīng)常需要在 WiFi 和 4G 之間進(jìn)行切換,比如我們在家里時使用 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)識一條連接,那么一旦四元組的任何一個元素發(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,每個連接 ID 都能標(biāo)識這條連接。連接 ID 是由一端獨(dú)立選擇的,每個端(客戶端和服務(wù)端統(tǒng)稱為端)選擇連接 ID 供對端使用。也就是說,客戶端生成的連接 ID 供服務(wù)端使用(服務(wù)端發(fā)送數(shù)據(jù)時使用客戶端生成的連接 ID 作為目的連接 ID),反過來一樣的。
連接 ID 的主要功能是確保底層協(xié)議(UDP、IP 及更底層的協(xié)議棧)發(fā)生地址變更(比如 IP 地址變了,或者端口號變了)時不會導(dǎo)致一個 QUIC 連接的數(shù)據(jù)包被傳輸?shù)藉e誤的 QUIC 終端(客戶端和服務(wù)端統(tǒng)稱為終端)上。
2.2.2 QUIC 的連接遷移過程
QUIC 限制連接遷移為僅客戶端可以發(fā)起,客戶端負(fù)責(zé)發(fā)起所有遷移。如果客戶端接收到了一個未知的服務(wù)器發(fā)來的數(shù)據(jù)包,那么客戶端必須丟棄這些數(shù)據(jù)包。
如圖 14 所示,連接遷移過程總共需要四個步驟。
連接遷移之前,客戶端使用 IP1 和服務(wù)端進(jìn)行通信;
客戶端 IP 變成 IP2,并且使用 IP2 發(fā)送非探測幀給服務(wù)端;
啟動路徑驗證(雙方都需要互相驗證),通過 PATH_CHANLLENGE 幀和 PATH_RESPONSE 幀進(jìn)行驗證。
驗證通過后,使用 IP2 進(jìn)行通信。
圖 14- 連接遷移流程圖
2.3 解決 TCP 隊頭阻塞問題
在 HTTP/2 中引入了流的概念。目的是實現(xiàn) 多個請求在同一個連接上并發(fā),從而提升網(wǎng)頁加載的效率。
圖 15-QUIC 解決 TCP 隊頭阻塞問題
由圖 15 來看,假設(shè)有兩個請求同時發(fā)送,紅色的是請求 1,藍(lán)色的是請求 2,這兩個請求在兩條不同的流中進(jìn)行傳輸。假設(shè)在傳輸過程中,請求 1 的某個數(shù)據(jù)包丟了,如果是 TCP,即使請求 2 的所有數(shù)據(jù)包都收到了,但是也只能阻塞在內(nèi)核緩沖區(qū)中,無法交給應(yīng)用層。但是 QUIC 就不一樣了,請求 1 的數(shù)據(jù)包丟了只會阻塞請求 1,請求 2 不會受到阻塞。
有些人不禁發(fā)問,不是說 HTTP2 也有流的概念嗎,為什么只有 QUIC 才能解決呢,這個根本原因就在于,HTTP2 的傳輸層用的 TCP,TCP 的實現(xiàn)是在內(nèi)核態(tài)的,而流是實現(xiàn)在用戶態(tài)度,TCP 是看不到“流”的,所以在 TCP 中,它不知道這個數(shù)據(jù)包是請求 1 還是請求 2 的,只會根據(jù) seq number 來判斷包的先后順序。
2.4 更優(yōu)的擁塞控制算法
擁塞控制算法中最重要的一個參數(shù)是 RTT,RTT 的準(zhǔn)確性決定了擁塞控制算法的準(zhǔn)確性;然而,TCP 的 RTT 測量往往不準(zhǔn)確,QUIC 的 RTT 測量是準(zhǔn)確的。
圖 16-TCP 計算 RTT
如圖 16 所示:由于網(wǎng)絡(luò)中經(jīng)常出現(xiàn)丟包,需要重傳,在 TCP 協(xié)議中,初始包和重傳包的序號是一樣的,擁塞控制算法進(jìn)行計算 RTT 的時候,無法區(qū)別是初始包還是重傳包,這將導(dǎo)致 RTT 的計算值要么偏大,要么偏小。
圖 17-QUIC 計算 RTT
如圖 17 所示:QUIC 通過 Packet Number 來標(biāo)識包的序號,而且規(guī)定 Packet Number 只能單調(diào)遞增,這也就解決了初始包和重傳包的二義性。從而保證 RTT 的值是準(zhǔn)確的。
另外,不同于 TCP,QUIC 的擁塞控制算法是可插拔的,由于其實現(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候網(wǎng)絡(luò)特別卡,數(shù)據(jù)包丟在中間了,發(fā)送方就需要重傳,那么怎么判斷是否擁塞了,重傳要怎么重傳法,按照什么算法進(jìn)行發(fā)送數(shù)據(jù)才能盡可能避免數(shù)據(jù)包在中間路徑丟掉,這是擁塞控制的核心。
所以,流量控制解決的是接收方的接收能力問題,一般采用滑動窗口算法;擁塞控制要解決的是中間傳輸?shù)臅r候網(wǎng)絡(luò)是否擁堵的問題,一般采用慢啟動、擁塞避免、擁塞恢復(fù)、快速重傳等算法。
圖 18-QUIC 流量控制
QUIC 是雙級流控,不僅有連接這一個級別的流控,還有流這個級別的流控。如下圖所示,每個流都有自己的可用窗口,可用窗口的大小取決于最大窗口數(shù)減去發(fā)送出去的最大偏移數(shù),跟中間已經(jīng)發(fā)送出去的數(shù)據(jù)包,是否按順序收到了對端的 ACK 無關(guān)。
QUIC 協(xié)議如何優(yōu)化
QUIC 協(xié)議定義了很多優(yōu)秀的功能,但是在實現(xiàn)的過程中,我們會遇到很多問題導(dǎo)致無法達(dá)到預(yù)期的性能,比如 0-RTT 率很低,連接遷移失敗率很高等等。
3.1 QUIC 的 0-RTT 成功率不高
導(dǎo)致 0-RTT 成功率不高的原因一般有如下幾個:
1. 服務(wù)端一般都是集群,對于客戶端來說,處理請求的服務(wù)端是不固定的,新的請求到來時,如果當(dāng)前 client 沒有請求過該服務(wù)器,則服務(wù)器上沒有相關(guān)會話信息,會把該請求當(dāng)做一個新的連接來處理,重新走 1-RTT。
針對此種情況,我們可以考慮集群中所有的服務(wù)器使用相同的 ticket 文件。
2. 客戶端 IP 不是固定的,在發(fā)生連接遷移時,服務(wù)端下發(fā)的 token 融合了客戶端的 IP,這個 IP 變化了的話,攜帶 token 服務(wù)端校驗不過,0-RTT 會失敗。
針對這個問題,我們可以考慮采用如圖 19 所示的方法,使用設(shè)備信息或者 APP 信息來生成 token,唯一標(biāo)識一個客戶端。
圖 19- 使用設(shè)備信息提高 0-RTT 的成功率
3. Session Ticket 過期時間默認(rèn)是 2 天,超過 2 天后就會導(dǎo)致 0-RTT 失敗,然后降級走 1-RTT。可以考慮增長過期時間。
3.2 實現(xiàn)連接遷移并不容易。
連接遷移的實現(xiàn),不可避開的兩個問題:一個是四層負(fù)載均衡器對連接遷移的影響,一個是七層負(fù)載均衡器對連接遷移的影響。
四層負(fù)載均衡器的影響:LVS、DPVS 等四層負(fù)載均衡工具基于四元組進(jìn)行轉(zhuǎn)發(fā),當(dāng)連接遷移發(fā)生時,四元組會發(fā)生變化,該組件就會把同一個請求的數(shù)據(jù)包發(fā)送到不同的后端服務(wù)器上,導(dǎo)致連接遷移失??;
七層負(fù)載均衡器的影響(QUIC 服務(wù)器多核的影響):由于多核的影響,一般服務(wù)器會有多個 QUIC 服務(wù)端進(jìn)程,每個進(jìn)程負(fù)載處理不同的連接。內(nèi)核收到數(shù)據(jù)包后,會根據(jù)二元組(源 IP、源 port)選擇已經(jīng)存在的連接,并把數(shù)據(jù)包交給對應(yīng)的 socket。在連接遷移發(fā)生時,源地址發(fā)生改變,可能會讓接下來的數(shù)據(jù)包去到不同的進(jìn)程,影響 socket 數(shù)據(jù)的接收。
如何解決以上兩個問題?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,四元組查找不到時,就必須使用連接 ID 進(jìn)行查找 socket。但是內(nèi)核代碼又不能去修改(不可能去更新所有服務(wù)器的內(nèi)核版本),那么我們可以使用 eBPF 的方法進(jìn)行解決。如下圖 20 所示:
圖 20- 多核 QUIC 服務(wù)器解決連接遷移問題
3.3 UDP 被限速或禁閉
業(yè)內(nèi)統(tǒng)計數(shù)據(jù)全球有 7% 地區(qū)的運(yùn)營商對 UDP 有限速或者禁閉,除了運(yùn)營商還有很多企業(yè)、公共場合也會限制 UDP 流量甚至禁用 UDP。這對使用 UDP 來承載 QUIC 協(xié)議的場景會帶來致命的傷害。對此,我們可以采用多路競速的方式使用 TCP 和 QUIC 同時建連。除了在建連進(jìn)行競速以外,還可以對網(wǎng)絡(luò) QUIC 和 TCP 的傳輸延時進(jìn)行實時監(jiān)控和對比,如果有鏈路對 UDP 進(jìn)行了限速,可以動態(tài)從 QUIC 切換到 TCP。
圖 21-QUIC 和 TCP 協(xié)議競速
3.4 QUIC 對 CPU 消耗大
相對于 TCP,為什么 QUIC 更消耗資源?
QUIC 在用戶態(tài)實現(xiàn),需要更多的內(nèi)核空間與用戶空間的數(shù)據(jù)拷貝和上下文切換;
QUIC 的 ACK 報文也是加密的,TCP 是明文的。
內(nèi)核知道 TCP 連接的狀態(tài),不用為每一個數(shù)據(jù)包去做諸如查找目的路由、防火墻規(guī)則等操作,只需要在 tcp 連接建立的時候做一次即可,然而 QUIC 不行;
總的來說,QUIC 服務(wù)端消耗 CPU 的地方主要有三個:密碼算法的開銷;udp 收發(fā)包的開銷;協(xié)議棧的開銷;
針對這些,我們可以適當(dāng)采取優(yōu)化措施來:
使用 Intel 硬件加速卡卸載 TLS 握手
開啟 GSO 功能。
數(shù)據(jù)在傳輸過程中,可以將一輪中所有的 ACK 解析后再同時進(jìn)行處理,避免處理大量的 ACK。
適當(dāng)將 QUIC 的包長限制調(diào)高(比如從默認(rèn)的 1200 調(diào)到 1400 個字節(jié))
減少協(xié)議棧的內(nèi)存拷貝
QUIC 的性能
從公開的數(shù)據(jù)來看,國內(nèi)各個廠(騰訊、阿里、字節(jié)、華為、OPPO、網(wǎng)易等等)使用了 QUIC 協(xié)議后,都有很大的提升,比如網(wǎng)易上了 QUIC 后,響應(yīng)速度提升 45%,請求錯誤率降低 50%;比如字節(jié)火山引擎使用 QUIC 后,建連耗時降低 20%~30%;比如騰訊使用 QUIC 后,在騰訊會議、直播、游戲等場景耗時也降低 30%;
圖 22- 字節(jié)火山引擎 QUIC 業(yè)務(wù)收益
總 結(jié)
QUIC 協(xié)議的出現(xiàn),為 HTTP/3 奠定了基礎(chǔ)。這是近些年在 web 協(xié)議上最大的變革,也是最優(yōu)秀的一次實踐。面對新的協(xié)議,我們總是有著各種各樣的擔(dān)憂,誠然,QUIC 協(xié)議在穩(wěn)定性上在成熟度上,的確還不如 TCP 協(xié)議,但是經(jīng)過近幾年的發(fā)展,成熟度已經(jīng)相當(dāng)不錯了,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文章
269瀏覽量
21591 -
HTTP
+關(guān)注
關(guān)注
0文章
511瀏覽量
31412 -
網(wǎng)絡(luò)通信
+關(guān)注
關(guān)注
4文章
814瀏覽量
29886 -
Quic
+關(guān)注
關(guān)注
0文章
25瀏覽量
7316
原文標(biāo)題:一文讀懂 QUIC 協(xié)議:更快、更穩(wěn)、更高效的網(wǎng)絡(luò)通信
文章出處:【微信號:AI前線,微信公眾號:AI前線】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論