科普:QUIC 協(xié)議原理分析
作者介紹:lancelot,騰訊資深研發(fā)工程師荸频。目前主要負(fù)責(zé)騰訊 stgw(騰訊安全云網(wǎng)關(guān))的相關(guān)工作狈谊,整體推進(jìn)騰訊內(nèi)部及騰訊公有云,混合云的七層負(fù)載均衡及全站 HTTPS 接入籽腕。對(duì) HTTPS,SPDY纸俭,HTTP2皇耗,QUIC 等應(yīng)用層協(xié)議、高性能服務(wù)器技術(shù)揍很、云網(wǎng)絡(luò)技術(shù)郎楼、用戶訪問速度、分布式文件傳輸?shù)扔休^深的理解窒悔。
本文系由“騰訊技術(shù)工程官方號(hào)”公眾號(hào)與“InfoQ”公眾號(hào)合辦的“騰訊技術(shù)工程”專欄第二篇文章(第一篇回顧:QQ相冊(cè)后臺(tái)存儲(chǔ)架構(gòu)重構(gòu)與跨IDC容災(zāi)實(shí)踐)呜袁,新的一年,騰訊技術(shù)工程專欄將為大家提供更多的騰訊技術(shù)干貨與落地實(shí)踐简珠。
本文將主要介紹 QUIC 協(xié)議產(chǎn)生的背景和核心特性阶界。
寫在前面
如果你的 App虹钮,在不需要任何修改的情況下就能提升 15% 以上的訪問速度。特別是弱網(wǎng)絡(luò)的時(shí)候能夠提升 20% 以上的訪問速度膘融。
如果你的 App芙粱,在頻繁切換 4G 和 WIFI 網(wǎng)絡(luò)的情況下,不會(huì)斷線氧映,不需要重連春畔,用戶無任何感知。如果你的 App岛都,既需要 TLS 的安全律姨,也想實(shí)現(xiàn) HTTP2 多路復(fù)用的強(qiáng)大。
如果你剛剛才聽說 HTTP2 是下一代互聯(lián)網(wǎng)協(xié)議臼疫,如果你剛剛才關(guān)注到 TLS1.3 是一個(gè)革命性具有里程碑意義的協(xié)議择份,但是這兩個(gè)協(xié)議卻一直在被另一個(gè)更新興的協(xié)議所影響和挑戰(zhàn)。
如果這個(gè)新興的協(xié)議多矮,它的名字就叫做“快”缓淹,并且正在標(biāo)準(zhǔn)化為新一代的互聯(lián)網(wǎng)傳輸協(xié)議。
你愿意花一點(diǎn)點(diǎn)時(shí)間了解這個(gè)協(xié)議嗎塔逃?你愿意投入精力去研究這個(gè)協(xié)議嗎讯壶?你愿意全力推動(dòng)業(yè)務(wù)來使用這個(gè)協(xié)議嗎?
QUIC 概述
Quic 全稱 quick udp internet connection [1]湾盗,“快速 UDP 互聯(lián)網(wǎng)連接”伏蚊,(和英文 quick 諧音,簡(jiǎn)稱“快”)是由 google 提出的使用 udp 進(jìn)行多路并發(fā)傳輸?shù)膮f(xié)議格粪。
Quic 相比現(xiàn)在廣泛應(yīng)用的 http2+tcp+tls 協(xié)議有如下優(yōu)勢(shì) [2]:
- 減少了 TCP 三次握手及 TLS 握手時(shí)間躏吊。
- 改進(jìn)的擁塞控制。
- 避免隊(duì)頭阻塞的多路復(fù)用帐萎。
- 連接遷移比伏。
- 前向冗余糾錯(cuò)。
為什么需要 QUIC
從上個(gè)世紀(jì) 90 年代互聯(lián)網(wǎng)開始興起一直到現(xiàn)在疆导,大部分的互聯(lián)網(wǎng)流量傳輸只使用了幾個(gè)網(wǎng)絡(luò)協(xié)議赁项。使用 IPv4 進(jìn)行路由,使用 TCP 進(jìn)行連接層面的流量控制澈段,使用 SSL/TLS 協(xié)議實(shí)現(xiàn)傳輸安全悠菜,使用 DNS 進(jìn)行域名解析,使用 HTTP 進(jìn)行應(yīng)用數(shù)據(jù)的傳輸败富。
而且近三十年來悔醋,這幾個(gè)協(xié)議的發(fā)展都非常緩慢。TCP 主要是擁塞控制算法的改進(jìn)兽叮,SSL/TLS 基本上停留在原地芬骄,幾個(gè)小版本的改動(dòng)主要是密碼套件的升級(jí)猾愿,TLS1.3[3] 是一個(gè)飛躍式的變化,但截止到今天德玫,還沒有正式發(fā)布匪蟀。IPv4 雖然有一個(gè)大的進(jìn)步椎麦,實(shí)現(xiàn)了 IPv6宰僧,DNS 也增加了一個(gè)安全的 DNSSEC,但和 IPv6 一樣观挎,部署進(jìn)度較慢琴儿。
隨著移動(dòng)互聯(lián)網(wǎng)快速發(fā)展以及物聯(lián)網(wǎng)的逐步興起,網(wǎng)絡(luò)交互的場(chǎng)景越來越豐富嘁捷,網(wǎng)絡(luò)傳輸?shù)膬?nèi)容也越來越龐大造成,用戶對(duì)網(wǎng)絡(luò)傳輸效率和 WEB 響應(yīng)速度的要求也越來越高。
一方面是歷史悠久使用廣泛的古老協(xié)議雄嚣,另外一方面用戶的使用場(chǎng)景對(duì)傳輸性能的要求又越來越高晒屎。如下幾個(gè)由來已久的問題和矛盾就變得越來越突出。
- 協(xié)議歷史悠久導(dǎo)致中間設(shè)備僵化缓升。
- 依賴于操作系統(tǒng)的實(shí)現(xiàn)導(dǎo)致協(xié)議本身僵化鼓鲁。
- 建立連接的握手延遲大。
- 隊(duì)頭阻塞港谊。
這里分小節(jié)簡(jiǎn)單說明一下:
中間設(shè)備的僵化
可能是 TCP 協(xié)議使用得太久骇吭,也非常可靠歧寺。所以我們很多中間設(shè)備燥狰,包括防火墻、NAT 網(wǎng)關(guān)斜筐,整流器等出現(xiàn)了一些約定俗成的動(dòng)作龙致。
比如有些防火墻只允許通過 80 和 443,不放通其他端口顷链。NAT 網(wǎng)關(guān)在轉(zhuǎn)換網(wǎng)絡(luò)地址時(shí)重寫傳輸層的頭部目代,有可能導(dǎo)致雙方無法使用新的傳輸格式。整流器和中間代理有時(shí)候出于安全的需要蕴潦,會(huì)刪除一些它們不認(rèn)識(shí)的選項(xiàng)字段像啼。
TCP 協(xié)議本來是支持端口、選項(xiàng)及特性的增加和修改潭苞。但是由于 TCP 協(xié)議和知名端口及選項(xiàng)使用的歷史太悠久忽冻,中間設(shè)備已經(jīng)依賴于這些潛規(guī)則,所以對(duì)這些內(nèi)容的修改很容易遭到中間環(huán)節(jié)的干擾而失敗此疹。
而這些干擾僧诚,也導(dǎo)致很多在 TCP 協(xié)議上的優(yōu)化變得小心謹(jǐn)慎遮婶,步履維艱。
依賴于操作系統(tǒng)的實(shí)現(xiàn)導(dǎo)致協(xié)議僵化
TCP 是由操作系統(tǒng)在內(nèi)核西方棧層面實(shí)現(xiàn)的湖笨,應(yīng)用程序只能使用旗扑,不能直接修改。雖然應(yīng)用程序的更新迭代非炒仁。快速和簡(jiǎn)單臀防。但是 TCP 的迭代卻非常緩慢,原因就是操作系統(tǒng)升級(jí)很麻煩边败。
現(xiàn)在移動(dòng)終端更加流行袱衷,但是移動(dòng)端部分用戶的操作系統(tǒng)升級(jí)依然可能滯后數(shù)年時(shí)間。PC 端的系統(tǒng)升級(jí)滯后得更加嚴(yán)重笑窜,windows xp 現(xiàn)在還有大量用戶在使用致燥,盡管它已經(jīng)存在快 20 年。
服務(wù)端系統(tǒng)不依賴用戶升級(jí)排截,但是由于操作系統(tǒng)升級(jí)涉及到底層軟件和運(yùn)行庫的更新嫌蚤,所以也比較保守和緩慢。
這也就意味著即使 TCP 有比較好的特性更新断傲,也很難快速推廣脱吱。比如 TCP Fast Open。它雖然 2013 年就被提出了艳悔,但是 Windows 很多系統(tǒng)版本依然不支持它急凰。
建立連接的握手延遲大
不管是 HTTP1.0/1.1 還是 HTTPS,HTTP2猜年,都使用了 TCP 進(jìn)行傳輸抡锈。HTTPS 和 HTTP2 還需要使用 TLS 協(xié)議來進(jìn)行安全傳輸。這就出現(xiàn)了兩個(gè)握手延遲:
1.TCP 三次握手導(dǎo)致的 TCP 連接建立的延遲乔外。
2.TLS 完全握手需要至少 2 個(gè) RTT 才能建立床三,簡(jiǎn)化握手需要 1 個(gè) RTT 的握手延遲。
對(duì)于很多短連接場(chǎng)景杨幼,這樣的握手延遲影響很大撇簿,且無法消除。
隊(duì)頭阻塞
隊(duì)頭阻塞主要是 TCP 協(xié)議的可靠性機(jī)制引入的差购。TCP 使用序列號(hào)來標(biāo)識(shí)數(shù)據(jù)的順序四瘫,數(shù)據(jù)必須按照順序處理,如果前面的數(shù)據(jù)丟失欲逃,后面的數(shù)據(jù)就算到達(dá)了也不會(huì)通知應(yīng)用層來處理找蜜。
另外 TLS 協(xié)議層面也有一個(gè)隊(duì)頭阻塞,因?yàn)?TLS 協(xié)議都是按照 record 來處理數(shù)據(jù)的稳析,如果一個(gè) record 中丟失了數(shù)據(jù)洗做,也會(huì)導(dǎo)致整個(gè) record 無法正確處理弓叛。
概括來講,TCP 和 TLS1.2 之前的協(xié)議存在著結(jié)構(gòu)性的問題诚纸,如果繼續(xù)在現(xiàn)有的 TCP撰筷、TLS 協(xié)議之上實(shí)現(xiàn)一個(gè)全新的應(yīng)用層協(xié)議,依賴于操作系統(tǒng)畦徘、中間設(shè)備還有用戶的支持毕籽。部署成本非常高,阻力非常大旧烧。
所以 QUIC 協(xié)議選擇了 UDP影钉,因?yàn)?UDP 本身沒有連接的概念,不需要三次握手掘剪,優(yōu)化了連接建立的握手延遲,同時(shí)在應(yīng)用程序?qū)用鎸?shí)現(xiàn)了 TCP 的可靠性奈虾,TLS 的安全性和 HTTP2 的并發(fā)性夺谁,只需要用戶端和服務(wù)端的應(yīng)用程序支持 QUIC 協(xié)議,完全避開了操作系統(tǒng)和中間設(shè)備的限制肉微。
QUIC 核心特性
連接建立延時(shí)低
0RTT 建連可以說是 QUIC 相比 HTTP2 最大的性能優(yōu)勢(shì)匾鸥。那什么是 0RTT 建連呢?這里面有兩層含義碉纳。
- 傳輸層 0RTT 就能建立連接勿负。
- 加密層 0RTT 就能建立加密連接。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 1 HTTPS 及 QUIC 建連過程</figcaption>
</figure>
比如上圖左邊是 HTTPS 的一次完全握手的建連過程劳曹,需要 3 個(gè) RTT奴愉。就算是 Session Resumption[14],也需要至少 2 個(gè) RTT铁孵。
而 QUIC 呢锭硼?由于建立在 UDP 的基礎(chǔ)上,同時(shí)又實(shí)現(xiàn)了 0RTT 的安全握手蜕劝,所以在大部分情況下檀头,只需要 0 個(gè) RTT 就能實(shí)現(xiàn)數(shù)據(jù)發(fā)送,在實(shí)現(xiàn)前向加密 [15] 的基礎(chǔ)上岖沛,并且 0RTT 的成功率相比 TLS 的 Sesison Ticket[13] 要高很多暑始。
改進(jìn)的擁塞控制
TCP 的擁塞控制實(shí)際上包含了四個(gè)算法:慢啟動(dòng),擁塞避免婴削,快速重傳廊镜,快速恢復(fù) [22]。
QUIC 協(xié)議當(dāng)前默認(rèn)使用了 TCP 協(xié)議的 Cubic 擁塞控制算法 [6]馆蠕,同時(shí)也支持 CubicBytes, Reno, RenoBytes, BBR, PCC 等擁塞控制算法。
從擁塞算法本身來看瞻鹏,QUIC 只是按照 TCP 協(xié)議重新實(shí)現(xiàn)了一遍贴汪,那么 QUIC 協(xié)議到底改進(jìn)在哪些方面呢?主要有如下幾點(diǎn):
可插拔
什么叫可插拔呢颂郎?就是能夠非常靈活地生效,變更和停止容为。體現(xiàn)在如下方面:
- 應(yīng)用程序?qū)用婢湍軐?shí)現(xiàn)不同的擁塞控制算法乓序,不需要操作系統(tǒng),不需要內(nèi)核支持坎背。這是一個(gè)飛躍替劈,因?yàn)閭鹘y(tǒng)的 TCP 擁塞控制,必須要端到端的網(wǎng)絡(luò)協(xié)議棧支持得滤,才能實(shí)現(xiàn)控制效果陨献。而內(nèi)核和操作系統(tǒng)的部署成本非常高,升級(jí)周期很長懂更,這在產(chǎn)品快速迭代眨业,網(wǎng)絡(luò)爆炸式增長的今天,顯然有點(diǎn)滿足不了需求沮协。
- 即使是單個(gè)應(yīng)用程序的不同連接也能支持配置不同的擁塞控制龄捡。就算是一臺(tái)服務(wù)器,接入的用戶網(wǎng)絡(luò)環(huán)境也千差萬別慷暂,結(jié)合大數(shù)據(jù)及人工智能處理聘殖,我們能為各個(gè)用戶提供不同的但又更加精準(zhǔn)更加有效的擁塞控制。比如 BBR 適合行瑞,Cubic 適合奸腺。
- 應(yīng)用程序不需要停機(jī)和升級(jí)就能實(shí)現(xiàn)擁塞控制的變更,我們?cè)诜?wù)端只需要修改一下配置蘑辑,reload 一下洋机,完全不需要停止服務(wù)就能實(shí)現(xiàn)擁塞控制的切換。
STGW 在配置層面進(jìn)行了優(yōu)化洋魂,我們可以針對(duì)不同業(yè)務(wù)绷旗,不同網(wǎng)絡(luò)制式,甚至不同的 RTT副砍,使用不同的擁塞控制算法衔肢。
單調(diào)遞增的 Packet Number
TCP 為了保證可靠性,使用了基于字節(jié)序號(hào)的 Sequence Number 及 Ack 來確認(rèn)消息的有序到達(dá)豁翎。
QUIC 同樣是一個(gè)可靠的協(xié)議角骤,它使用 Packet Number 代替了 TCP 的 sequence number,并且每個(gè) Packet Number 都嚴(yán)格遞增,也就是說就算 Packet N 丟失了邦尊,重傳的 Packet N 的 Packet Number 已經(jīng)不是 N背桐,而是一個(gè)比 N 大的值。而 TCP 呢蝉揍,重傳 segment 的 sequence number 和原始的 segment 的 Sequence Number 保持不變链峭,也正是由于這個(gè)特性,引入了 Tcp 重傳的歧義問題又沾。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 2 Tcp 重傳歧義性</figcaption>
</figure>
如上圖所示弊仪,超時(shí)事件 RTO 發(fā)生后,客戶端發(fā)起重傳杖刷,然后接收到了 Ack 數(shù)據(jù)励饵。由于序列號(hào)一樣,這個(gè) Ack 數(shù)據(jù)到底是原始請(qǐng)求的響應(yīng)還是重傳請(qǐng)求的響應(yīng)呢滑燃?不好判斷役听。
如果算成原始請(qǐng)求的響應(yīng),但實(shí)際上是重傳請(qǐng)求的響應(yīng)(上圖左)不瓶,會(huì)導(dǎo)致采樣 RTT 變大禾嫉。如果算成重傳請(qǐng)求的響應(yīng),但實(shí)際上是原始請(qǐng)求的響應(yīng)蚊丐,又很容易導(dǎo)致采樣 RTT 過小。
由于 Quic 重傳的 Packet 和原始 Packet 的 Pakcet Number 是嚴(yán)格遞增的艳吠,所以很容易就解決了這個(gè)問題麦备。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 3 Quic 重傳沒有歧義性</figcaption>
</figure>
如上圖所示,RTO 發(fā)生后昭娩,根據(jù)重傳的 Packet Number 就能確定精確的 RTT 計(jì)算凛篙。如果 Ack 的 Packet Number 是 N+M,就根據(jù)重傳請(qǐng)求計(jì)算采樣 RTT栏渺。如果 Ack 的 Pakcet Number 是 N呛梆,就根據(jù)原始請(qǐng)求的時(shí)間計(jì)算采樣 RTT,沒有歧義性磕诊。
但是單純依靠嚴(yán)格遞增的 Packet Number 肯定是無法保證數(shù)據(jù)的順序性和可靠性填物。QUIC 又引入了一個(gè) Stream Offset 的概念。
即一個(gè) Stream 可以經(jīng)過多個(gè) Packet 傳輸霎终,Packet Number 嚴(yán)格遞增滞磺,沒有依賴。但是 Packet 里的 Payload 如果是 Stream 的話莱褒,就需要依靠 Stream 的 Offset 來保證應(yīng)用數(shù)據(jù)的順序击困。如錯(cuò)誤! 未找到引用源。所示广凸,發(fā)送端先后發(fā)送了 Pakcet N 和 Pakcet N+1阅茶,Stream 的 Offset 分別是 x 和 x+y蛛枚。
假設(shè) Packet N 丟失了,發(fā)起重傳脸哀,重傳的 Packet Number 是 N+2蹦浦,但是它的 Stream 的 Offset 依然是 x,這樣就算 Packet N + 2 是后到的企蹭,依然可以將 Stream x 和 Stream x+y 按照順序組織起來白筹,交給應(yīng)用程序處理。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 4 Stream Offset 保證有序性</figcaption>
</figure>
不允許 Reneging
什么叫 Reneging 呢谅摄?就是接收方丟棄已經(jīng)接收并且上報(bào)給 SACK 選項(xiàng)的內(nèi)容 [8]徒河。TCP 協(xié)議不鼓勵(lì)這種行為,但是協(xié)議層面允許這樣的行為送漠。主要是考慮到服務(wù)器資源有限顽照,比如 Buffer 溢出,內(nèi)存不夠等情況闽寡。
Reneging 對(duì)數(shù)據(jù)重傳會(huì)產(chǎn)生很大的干擾代兵。因?yàn)?Sack 都已經(jīng)表明接收到了,但是接收端事實(shí)上丟棄了該數(shù)據(jù)爷狈。
QUIC 在協(xié)議層面禁止 Reneging植影,一個(gè) Packet 只要被 Ack,就認(rèn)為它一定被正確接收涎永,減少了這種干擾思币。
更多的 Ack 塊
TCP 的 Sack 選項(xiàng)能夠告訴發(fā)送方已經(jīng)接收到的連續(xù) Segment 的范圍,方便發(fā)送方進(jìn)行選擇性重傳羡微。
由于 TCP 頭部最大只有 60 個(gè)字節(jié)谷饿,標(biāo)準(zhǔn)頭部占用了 20 字節(jié),所以 Tcp Option 最大長度只有 40 字節(jié)妈倔,再加上 Tcp Timestamp option 占用了 10 個(gè)字節(jié) [25]博投,所以留給 Sack 選項(xiàng)的只有 30 個(gè)字節(jié)。
每一個(gè) Sack Block 的長度是 8 個(gè)盯蝴,加上 Sack Option 頭部 2 個(gè)字節(jié)毅哗,也就意味著 Tcp Sack Option 最大只能提供 3 個(gè) Block。
但是 Quic Ack Frame 可以同時(shí)提供 256 個(gè) Ack Block结洼,在丟包率比較高的網(wǎng)絡(luò)下黎做,更多的 Sack Block 可以提升網(wǎng)絡(luò)的恢復(fù)速度,減少重傳量松忍。
Ack Delay 時(shí)間
Tcp 的 Timestamp 選項(xiàng)存在一個(gè)問題 [25]蒸殿,它只是回顯了發(fā)送方的時(shí)間戳,但是沒有計(jì)算接收端接收到 segment 到發(fā)送 Ack 該 segment 的時(shí)間。這個(gè)時(shí)間可以簡(jiǎn)稱為 Ack Delay宏所。
這樣就會(huì)導(dǎo)致 RTT 計(jì)算誤差酥艳。如下圖:
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;"></figcaption>
</figure>
可以認(rèn)為 TCP 的 RTT 計(jì)算:
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;"></figcaption>
</figure>
而 Quic 計(jì)算如下:
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;"></figcaption>
</figure>
當(dāng)然 RTT 的具體計(jì)算沒有這么簡(jiǎn)單,需要采樣爬骤,參考?xì)v史數(shù)值進(jìn)行平滑計(jì)算充石,參考如下公式 [9]。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;"></figcaption>
</figure>
基于 stream 和 connecton 級(jí)別的流量控制
QUIC 的流量控制 [22] 類似 HTTP2霞玄,即在 Connection 和 Stream 級(jí)別提供了兩種流量控制骤铃。為什么需要兩類流量控制呢?主要是因?yàn)?QUIC 支持多路復(fù)用坷剧。
- Stream 可以認(rèn)為就是一條 HTTP 請(qǐng)求惰爬。
- Connection 可以類比一條 TCP 連接。多路復(fù)用意味著在一條 Connetion 上會(huì)同時(shí)存在多條 Stream惫企。既需要對(duì)單個(gè) Stream 進(jìn)行控制撕瞧,又需要針對(duì)所有 Stream 進(jìn)行總體控制。
QUIC 實(shí)現(xiàn)流量控制的原理比較簡(jiǎn)單:
通過 window_update 幀告訴對(duì)端自己可以接收的字節(jié)數(shù)狞尔,這樣發(fā)送方就不會(huì)發(fā)送超過這個(gè)數(shù)量的數(shù)據(jù)丛版。
通過 BlockFrame 告訴對(duì)端由于流量控制被阻塞了,無法發(fā)送數(shù)據(jù)偏序。
QUIC 的流量控制和 TCP 有點(diǎn)區(qū)別页畦,TCP 為了保證可靠性,窗口左邊沿向右滑動(dòng)時(shí)的長度取決于已經(jīng)確認(rèn)的字節(jié)數(shù)研儒。如果中間出現(xiàn)丟包寇漫,就算接收到了更大序號(hào)的 Segment,窗口也無法超過這個(gè)序列號(hào)殉摔。
但 QUIC 不同,就算此前有些 packet 沒有接收到记焊,它的滑動(dòng)只取決于接收到的最大偏移字節(jié)數(shù)逸月。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 5 Quic Flow Control</figcaption>
</figure>
針對(duì) Stream:
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;"></figcaption>
</figure>
針對(duì) Connection:
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;"></figcaption>
</figure>
同樣地,STGW 也在連接和 Stream 級(jí)別設(shè)置了不同的窗口數(shù)遍膜。
最重要的是碗硬,我們可以在內(nèi)存不足或者上游處理性能出現(xiàn)問題時(shí),通過流量控制來限制傳輸速率瓢颅,保障服務(wù)可用性恩尾。
沒有隊(duì)頭阻塞的多路復(fù)用
QUIC 的多路復(fù)用和 HTTP2 類似。在一條 QUIC 連接上可以并發(fā)發(fā)送多個(gè) HTTP 請(qǐng)求 (stream)挽懦。但是 QUIC 的多路復(fù)用相比 HTTP2 有一個(gè)很大的優(yōu)勢(shì)翰意。
QUIC 一個(gè)連接上的多個(gè) stream 之間沒有依賴。這樣假如 stream2 丟了一個(gè) udp packet,也只會(huì)影響 stream2 的處理冀偶。不會(huì)影響 stream2 之前及之后的 stream 的處理醒第。
這也就在很大程度上緩解甚至消除了隊(duì)頭阻塞的影響。
多路復(fù)用是 HTTP2 最強(qiáng)大的特性 [7]进鸠,能夠?qū)⒍鄺l請(qǐng)求在一條 TCP 連接上同時(shí)發(fā)出去稠曼。但也惡化了 TCP 的一個(gè)問題,隊(duì)頭阻塞 [11]客年,如下圖示:
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 6 HTTP2 隊(duì)頭阻塞</figcaption>
</figure>
HTTP2 在一個(gè) TCP 連接上同時(shí)發(fā)送 4 個(gè) Stream霞幅。其中 Stream1 已經(jīng)正確到達(dá),并被應(yīng)用層讀取量瓜。但是 Stream2 的第三個(gè) tcp segment 丟失了司恳,TCP 為了保證數(shù)據(jù)的可靠性,需要發(fā)送端重傳第 3 個(gè) segment 才能通知應(yīng)用層讀取接下去的數(shù)據(jù)榔至,雖然這個(gè)時(shí)候 Stream3 和 Stream4 的全部數(shù)據(jù)已經(jīng)到達(dá)了接收端抵赢,但都被阻塞住了。
不僅如此唧取,由于 HTTP2 強(qiáng)制使用 TLS铅鲤,還存在一個(gè) TLS 協(xié)議層面的隊(duì)頭阻塞 [12]。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 7 TLS 隊(duì)頭阻塞</figcaption>
</figure>
Record 是 TLS 協(xié)議處理的最小單位枫弟,最大不能超過 16K邢享,一些服務(wù)器比如 Nginx 默認(rèn)的大小就是 16K。由于一個(gè) record 必須經(jīng)過數(shù)據(jù)一致性校驗(yàn)才能進(jìn)行加解密淡诗,所以一個(gè) 16K 的 record骇塘,就算丟了一個(gè)字節(jié),也會(huì)導(dǎo)致已經(jīng)接收到的 15.99K 數(shù)據(jù)無法處理韩容,因?yàn)樗煌暾?/p>
那 QUIC 多路復(fù)用為什么能避免上述問題呢款违?
- QUIC 最基本的傳輸單元是 Packet,不會(huì)超過 MTU 的大小群凶,整個(gè)加密和認(rèn)證過程都是基于 Packet 的插爹,不會(huì)跨越多個(gè) Packet。這樣就能避免 TLS 協(xié)議存在的隊(duì)頭阻塞请梢。
- Stream 之間相互獨(dú)立赠尾,比如 Stream2 丟了一個(gè) Pakcet,不會(huì)影響 Stream3 和 Stream4毅弧。不存在 TCP 隊(duì)頭阻塞气嫁。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;">圖 8 QUIC 多路復(fù)用時(shí)沒有隊(duì)頭阻塞的問題</figcaption>
</figure>
當(dāng)然,并不是所有的 QUIC 數(shù)據(jù)都不會(huì)受到隊(duì)頭阻塞的影響够坐,比如 QUIC 當(dāng)前也是使用 Hpack 壓縮算法 [10]寸宵,由于算法的限制崖面,丟失一個(gè)頭部數(shù)據(jù)時(shí),可能遇到隊(duì)頭阻塞邓馒。
總體來說嘶朱,QUIC 在傳輸大量數(shù)據(jù)時(shí),比如視頻光酣,受到隊(duì)頭阻塞的影響很小疏遏。
加密認(rèn)證的報(bào)文
TCP 協(xié)議頭部沒有經(jīng)過任何加密和認(rèn)證,所以在傳輸過程中很容易被中間網(wǎng)絡(luò)設(shè)備篡改救军,注入和竊聽财异。比如修改序列號(hào)、滑動(dòng)窗口唱遭。這些行為有可能是出于性能優(yōu)化戳寸,也有可能是主動(dòng)攻擊。
但是 QUIC 的 packet 可以說是武裝到了牙齒拷泽。除了個(gè)別報(bào)文比如 PUBLIC_RESET 和 CHLO疫鹊,所有報(bào)文頭部都是經(jīng)過認(rèn)證的,報(bào)文 Body 都是經(jīng)過加密的司致。
這樣只要對(duì) QUIC 報(bào)文任何修改拆吆,接收端都能夠及時(shí)發(fā)現(xiàn),有效地降低了安全風(fēng)險(xiǎn)脂矫。
如下圖所示枣耀,紅色部分是 Stream Frame 的報(bào)文頭部,有認(rèn)證庭再。綠色部分是報(bào)文內(nèi)容捞奕,全部經(jīng)過加密。
<figure style="box-sizing: border-box; list-style: inherit; margin: 20px 0px; display: block; text-align: center;">
<figcaption style="box-sizing: border-box; list-style: inherit; font-size: 14px; color: rgb(153, 153, 153); text-align: center; max-width: 61.8%; margin: 8px auto;"></figcaption>
</figure>
連接遷移
一條 TCP 連接 [17] 是由四元組標(biāo)識(shí)的(源 IP拄轻,源端口颅围,目的 IP,目的端口)恨搓。什么叫連接遷移呢谷浅?就是當(dāng)其中任何一個(gè)元素發(fā)生變化時(shí),這條連接依然維持著奶卓,能夠保持業(yè)務(wù)邏輯不中斷。當(dāng)然這里面主要關(guān)注的是客戶端的變化撼玄,因?yàn)榭蛻舳瞬豢煽夭⑶揖W(wǎng)絡(luò)環(huán)境經(jīng)常發(fā)生變化夺姑,而服務(wù)端的 IP 和端口一般都是固定的。
比如大家使用手機(jī)在 WIFI 和 4G 移動(dòng)網(wǎng)絡(luò)切換時(shí)掌猛,客戶端的 IP 肯定會(huì)發(fā)生變化盏浙,需要重新建立和服務(wù)端的 TCP 連接眉睹。
又比如大家使用公共 NAT 出口時(shí),有些連接競(jìng)爭(zhēng)時(shí)需要重新綁定端口废膘,導(dǎo)致客戶端的端口發(fā)生變化竹海,同樣需要重新建立 TCP 連接。
針對(duì) TCP 的連接變化丐黄,MPTCP[5] 其實(shí)已經(jīng)有了解決方案斋配,但是由于 MPTCP 需要操作系統(tǒng)及網(wǎng)絡(luò)協(xié)議棧支持,部署阻力非常大灌闺,目前并不適用艰争。
所以從 TCP 連接的角度來講,這個(gè)問題是無解的桂对。
那 QUIC 是如何做到連接遷移呢甩卓?很簡(jiǎn)單,任何一條 QUIC 連接不再以 IP 及端口四元組標(biāo)識(shí)蕉斜,而是以一個(gè) 64 位的隨機(jī)數(shù)作為 ID 來標(biāo)識(shí)逾柿,這樣就算 IP 或者端口發(fā)生變化時(shí),只要 ID 不變宅此,這條連接依然維持著机错,上層業(yè)務(wù)邏輯感知不到變化,不會(huì)中斷诽凌,也就不需要重連毡熏。
由于這個(gè) ID 是客戶端隨機(jī)產(chǎn)生的,并且長度有 64 位侣诵,所以沖突概率非常低痢法。
其他亮點(diǎn)
此外,QUIC 還能實(shí)現(xiàn)前向冗余糾錯(cuò)杜顺,在重要的包比如握手消息發(fā)生丟失時(shí)财搁,能夠根據(jù)冗余信息還原出握手消息。
QUIC 還能實(shí)現(xiàn)證書壓縮躬络,減少證書傳輸量尖奔,針對(duì)包頭進(jìn)行驗(yàn)證等。
限于篇幅穷当,本文不再詳細(xì)介紹提茁,有興趣的可以參考文檔 [23] 和文檔 [4] 和文檔 [26]。
參考線索
[1]. https://www.chromium.org/quic
[2]. https://docs.google.com/document/d/1gY9-YNDNAB1eip-RTPbqphgySwSNSDHLq9D5Bty4FSU/edit
[3]. E. Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.3”, draft-ietf-tls-tls13-21, https://tools.ietf.org/html/draft-ietf-tls-tls13-21, July 03, 2017
[4]. Adam Langley,Wan-Teh Chang, “QUIC Crypto”馁菜,https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/edit, 20161206
[5]. https://www.multipath-tcp.org/
[6]. Ha, S., Rhee, I., and L. Xu, "CUBIC: A New TCP-Friendly High-Speed TCP Variant", ACM SIGOPS Operating System Review , 2008.
[7]. M. Belshe,BitGo, R. Peon, “Hypertext Transfer Protocol Version 2 (HTTP/2)”, RFC 7540, May 2015
[8]. M. Mathis,J. Mahdavi,S. Floyd,A. Romanow,“TCP Selective Acknowledgment Options”, rfc2018, https://tools.ietf.org/html/rfc2018, October 1996
[9]. V. Paxson茴扁,M. Allman,J. Chu汪疮,M. Sargent峭火,“Computing TCP's Retransmission Timer”毁习, rfc6298, https://tools.ietf.org/html/rfc6298, June 2011
[10]. R. Peon,H. Ruellan,“HPACK: Header Compression for HTTP/2”,RFC7541,May 2015
[11]. M. Scharf, Alcatel-Lucent Bell Labs, S. Kiesel, “Quantifying Head-of-Line Blocking in TCP and SCTP”, https://tools.ietf.org/id/draft-scharf-tcpm-reordering-00.html, July 15, 2013
[12]. Ilya Grigorik,“Optimizing TLS Record Size & Buffering Latency”, https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/, October 24, 2013
[13]. J. Salowey,H. Zhou,P. Eronen,H. Tschofenig, “Transport Layer Security (TLS) Session Resumption without Server-Side State”, RFC5077, January 2008
[14]. Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, DOI 10.17487/RFC5246, August 2008, http://www.rfc-editor.org/info/rfc5246.
[15]. Shirey, R., "Internet Security Glossary, Version 2", FYI , RFC 4949, August 2007
[16]. 羅成卖丸,“HTTPS性能優(yōu)化”纺且, http://www.infoq.com/cn/presentations/performance-optimization-of-https,F(xiàn)ebruary.2017
[17]. Postel, J., "Transmission Control Protocol", STD 7, RFC793, September 1981.
[18]. J. Postel,“User Datagram Protocol”, RFC768,August 1980
[19]. Q. Dang, S. Santesson,K. Moriarty,D. Brown.T. Polk, “Internet X.509 Public Key Infrastructure: Additional Algorithms and Identifiers for DSA and ECDSA”,RFC5758, January 2010
[20]. Bassham, L., Polk, W., and R. Housley, "Algorithms and Identifiers for the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3279, April 2002
[21]. D.Cooper,S.Santesson, S.Farrell,S. Boeyen,R. Housley,W.Polk, “Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile”, RFC5280, May 2008
[22]. M. Allman,V. Paxson,E. Blanton, "TCP Congestion Control”,RFC5681, September 2009
[23]. Robbie Shade, “Flow control in QUIC”, https://docs.google.com/document/d/1F2YfdDXKpy20WVKJueEf4abn_LVZHhMUMS5gX6Pgjl4/edit#, May, 2016,
[24]. ianswett , “QUIC fec v1”, https://docs.google.com/document/d/1Hg1SaLEl6T4rEU9j-isovCo8VEjjnuCPTcLNJewj7Nk/edit#heading=h.xgjl2srtytjt, 2016-02-19
[25]. D.Borman,B.Braden,V.Jacobson,R.Scheffenegger, Ed. “TCP Extensions for High Performance”,rfc7323, https://tools.ietf.org/html/rfc7323,September 2014
[26]. 羅成稍浆,“WEB加速载碌,協(xié)議先行”, https://zhuanlan.zhihu.com/p/27938635粹湃,july, 2017