You are on page 1of 32

Accessibility UX CSS JavaScript Performance Design Figma

罗宾·马克思 (↦ /author/robin-marx/) / 8月 23, 2021 / 6 (↦ #comments-http3-performance

HTTP/3:性能改进(第 2 部分)
快 速 摘 要 ↬ 经过近五年的开发,新的HTTP / 3协议已接近其最终形

式。让我们仔细看看 HTTP/3、拥塞控制、行头阻塞和 0-RTT 连接设


置的性能改进。

欢迎回到这个关于新的HTTP / 3协议的系列。在第 1 部分中,我们研究了


为什么我们需要 HTTP/3 (↦ https://www.smashingmagazine.com/2021/08/http3-core-
concepts-part1/) 和底层 QUIC 协议,以及它们的主要新功能是什么。

在第二部分中,我们将重点介绍 QUIC 和 HTTP/3 为网页加载带来的性能改进。


但是,我们也将对在实践中从这些新功能中可以预期的影响持怀疑态度。

正如我们将看到的,QUIC和HTTP / 3确实具有巨大的Web性能潜力,但主要适
用于慢速网络上的用户。如果您的普通访问者位于快速有线或蜂窝网络上,他
们可能不会从新协议中受益匪浅。但是,请注意,即使在通常使用快速上行链
路的国家和地区,最慢的1%到10%的受众(所谓的第99或第90百分位)仍然可能
会获得很多收益。这是因为HTTP / 3和QUIC主要帮助处理当今Internet上可能出
现的一些不常见但可能具有高影响的问题。

这部分比第一部分更具技术性,尽管它将大部分真正深入的东西卸载到外部资
源,重点是解释为什么这些东西对普通的Web开发人员很重要。

第 1 部分:HTTP/3 历史和核心概念 (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/)

本文针对的是刚接触 HTTP/3 和一般协议的人,主要讨论基础知


识。

第2部分:HTTP / 3性能特性

这一部分更深入,技术性更强。已经了解基础知识的人可以从这里
开始。
第 3 部分:实用的 HTTP/3 部署选项 (↦
https://www.smashingmagazine.com/2021/09/http3-practical-deployment-options-
part3/)

本系列的第三篇文章介绍了自己部署和测试 HTTP/3 所涉及的挑


战。它详细说明了如何以及是否应该更改网页和资源。

速度入门# (↦ #A-Primer-On-Speed)
讨论性能和“速度”很快就会变得复杂,因为许多潜在的方面都会导致网页加
载“缓慢”。因为我们在这里处理的是网络协议,所以我们将主要看网络方面,其
中两个是最重要的:延迟和带宽。

延迟可以粗略地定义为将数据包从A点(例如客户端)发送到B点(服务器)所
需的时间。它在物理上受到光速的限制,或者实际上,信号在电线或露天传播
的速度有多快。这意味着延迟通常取决于 A 和 B 之间的物理实际距离。

在地球上 (↦ https://www.youtube.com/watch?v=6bbN48zCNl8),这意味着典型的延迟在概
念上很小,大约在10到200毫秒之间。但是,这只是一种方法:对数据包的响应
也需要返回。双向延迟通常称为往返时间 (RTT)。

由于拥塞控制等功能(见下文),我们通常需要相当多的往返行程才能加载单
个文件。因此,即使是小于50毫秒的低延迟也可能累积相当大的延迟。这是内
容交付网络(CDN)存在的主要原因之一:它们将服务器放置在物理上更靠近
最终用户的位置,以尽可能减少延迟,从而减少延迟。

因此,带宽可以大致说是可以同时发送的数据包的数量。这有点难以解释,因
为它取决于介质的物理属性(例如,无线电波的使用频率),网络上的用户数
量以及互连不同子网的设备(因为它们通常每秒只能处理一定数量的数据
包)。

一个经常使用的比喻是用于运输水的管道。管道的长度是延迟,而管道的宽度
是带宽。然而,在互联网上,我们通常有一长串连接的管道,其中一些管道可
能比其他管道更宽(导致在最窄的链接处出现所谓的瓶颈)。因此,点 A 和点 B
之间的端到端带宽通常受到最慢子节的限制。

虽然本文的其余部分不需要对这些概念有完美的理解,但有一个共同的高级定
义会很好。有关更多信息,我建议您查看Ilya Grigorik在他的书《高性能浏览器
网络》中关于延迟和带宽的优秀章节 (↦ https://hpbn.co/primer-on-latency-and-
bandwidth/)。

拥塞控制# (↦ #Congestion-Control)

性能的一个方面是关于传输协议可以有效地使用网络的全部(物理)带宽(即
粗略地说,每秒可以发送或接收多少个数据包)。这反过来又会影响页面资源
的下载速度。有些人声称QUIC在某种程度上比TCP做得更好,但事实并非如
此。

您知道吗?

例如,TCP连接不只是开始以全带宽发送数据,因为这最终可能会
使网络过载(或拥塞)。这是因为,正如我们所说,每个网络链路
每秒只能(物理)处理一定量的数据。再给它一点,除了丢弃过多
的数据包之外,别无选择,导致数据包丢失。

如第 1 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-
part1/)所述,对于像 TCP 这样的可靠协议,从数据包丢失中恢复的
唯一方法是重新传输数据的新副本,这需要一次往返。特别是在高
延迟网络上(例如,RTT超过50毫秒),数据包丢失会严重影响性
能。

另一个问题是,我们事先不知道最大带宽是多少。它通常取决于端到端连接中
某个地方的瓶颈,但我们无法预测或知道这将在哪里。互联网也没有(尚未)
将链路容量信号传回端点的机制。

此外,即使我们知道可用的物理带宽,这并不意味着我们可以自己使用所有内
容。几个用户通常同时在网络上处于活动状态,每个用户都需要公平份额的可
用带宽。

因此,连接不知道它可以安全或公平地预先使用多少带宽,并且随着用户加
入,离开和使用网络,此带宽可能会发生变化。为了解决这个问题,TCP将不断
尝试通过使用称为拥塞控制的机制来发现一段时间内的可用带宽。

在连接开始时,它只发送几个数据包(实际上,范围在10到100个数据包之间,
或大约14到140 KB的数据),并等待一次往返,直到接收方发回这些数据包的
确认。如果它们都被确认,这意味着网络可以处理该发送速率,我们可以尝试
重复该过程,但使用更多数据(在实践中,发送速率通常会随着每次迭代而翻
倍)。
这样,发送速率将继续增长,直到某些数据包未被确认(这表示数据包丢失和
网络拥塞)。第一阶段通常称为“慢启动”。检测到数据包丢失后,TCP会降低发
送速率,并且(一段时间后)再次开始增加发送速率,尽管增量(小得多)。
此先减后增长逻辑对之后的每个数据包丢失重复。最终,这意味着TCP将不断尝
试达到其理想的公平带宽份额。此机制如图 1 所示。

(↦ https://hpbn.co/building-blocks-of-tcp/#congestion-avoidance-and-control)

图 1.TCP 拥塞控制的简化示例,从 10 个数据包的发送速率开始(改编自


hpbn.co (↦ https://hpbn.co/building-blocks-of-tcp/#congestion-avoidance-and-control)。(大预
览 (↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-
46f01eedd629/9d5e5ddd-7a90-48c6-84c5-dc5c335e2305/congestion-control.png))

这是对拥塞控制的一种极其简化的解释。在实践中,还有许多其他因素在起作
用,例如缓冲区膨胀 (↦ https://www.youtube.com/watch?v=ZeCIbCzGY6k),由于拥塞引起
的RTT波动 (↦ https://blog.apnic.net/2017/05/09/bbr-new-kid-tcp-block/),以及多个并发发送
者需要获得其公平份额的带宽 (↦ https://justinesherry.com/papers/ware-hotnets19.pdf)的事
实。因此,存在许多不同的拥塞控制算法,并且今天仍在发明大量算法,但没
有一种在所有情况下都能发挥最佳性能。

虽然TCP的拥塞控制使其健壮,但这也意味着需要一段时间才能达到最佳发送
速率,具体取决于RTT和实际可用带宽。对于网页加载,这种慢启动方法也会影
响指标,例如第一次内容性绘制,因为在前几次往返行程中只能传输少量数据

(数十到几百 KB)。(您可能听说过将关键数据保持在小于 14 KB (↦
htt // t th b /bl / iti l d th fi t 14kb/) 的建议
https://www.tunetheweb.com/blog/critical-resources-and-the-first-14kb/) 的建议。

因此,选择更激进的方法可以在高带宽和高延迟网络上带来更好的结果,特别
是如果您不关心偶尔的数据包丢失。这就是我再次看到许多关于QUIC如何工作
的错误解释的地方。

如第 1 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/)所述,从
理论上讲,QUIC 受数据包丢失(以及相关的线头 (HOL) 阻塞)的影响较
小,因为它独立处理每个资源的字节流上的数据包丢失。此外,QUIC在用户数
据报协议(UDP)上运行,与TCP不同,该协议没有内置拥塞控制功能。它允许
您尝试以所需的任何速率发送,并且不会重新传输丢失的数据。

这导致许多文章声称QUIC也不使用拥塞控制,QUIC可以开始以比UDP更高的速
率发送数据(依靠消除HOL阻塞来处理数据包丢失),这就是为什么QUIC比
TCP快得多。

实际上,事实并非如此 (↦ https://www.rfc-editor.org/rfc/rfc9002.html):QUIC实际上使用
与TCP非常相似的带宽管理技术。它也从较低的发送速率开始,并随着时间的
推移而增长,使用确认作为测量网络容量的关键机制。这是(以及其他原因)
因为QUIC需要可靠才能对HTTP之类的东西有用,因为它需要对其他QUIC(和
TCP!)连接公平,并且因为它的HOL阻塞删除实际上并不能很好地帮助防止数
据包丢失(正如我们将在下面看到的那样)。

但是,这并不意味着QUIC在如何管理带宽方面不能比TCP更聪明。这主要是因
为QUIC比TCP更灵活,更容易发展。正如我们所说,拥塞控制算法今天仍在大
力发展,例如,我们可能需要调整一些东西以充分利用5G (↦
https://dl.acm.org/doi/abs/10.1145/3387514.3405882)。

但是,TCP通常在操作系统(OS')内核中实现,这是一个安全且更受限制的环
境,对于大多数操作系统来说,它甚至不是开源的。因此,调整拥塞逻辑通常
仅由少数开发人员完成,并且演进速度很慢。

相比之下,大多数QUIC实现目前在“用户空间”(我们通常运行本机应用程序的
地方)中完成,并且是开源 (↦ https://github.com/quicwg/base-drafts/wiki/Implementations)
的,明确鼓励更广泛的开发人员进行实验(例如,Facebook (↦
https://research.fb.com/wp-content/uploads/2019/12/MVFST-RL-An-Asynchronous-RL-Framework-for-
Congestion-Control-with-Delayed-Actions.pdf)已经显示)。

另一个具体的例子是QUIC的延迟确认频率 (↦ https://tools.ietf.org/html/draft-iyengar-quic-
dl d k 02)扩展提案 默认情况下 QUIC 为每 2 个收到的数据包发送 个确
delayed-ack-02)扩展提案。默认情况下,QUIC 为每 2 个收到的数据包发送一个确
认,而此扩展允许端点确认,例如,每 10 个数据包一次。这已被证明可以在卫
星和非常高带宽的网络上带来巨大的速度优势,因为传输确认数据包的开销降
低了。为TCP添加这样的扩展需要很长时间才能被采用,而对于QUIC来说,部
署起来要容易得多。
因此,我们可以预期QUIC的灵活性将随着时间的推移带来更多的实验和更好的
拥塞控制算法,这反过来又可以向后移植到TCP以改进它。

您知道吗?

官方的 QUIC Recovery RFC 9002 (↦ https://www.rfc-


editor.org/rfc/rfc9002.html) 指定了 NewReno 拥塞控制算法的使用。虽然
这种方法很健壮,但它也有些过时,不再在实践中广泛使用。那
么,为什么它在QUIC RFC中呢?第一个原因是,当QUIC启动时,
NewReno是最新的拥塞控制算法,它本身就是标准化的。更高级的
算法,如BBR和CUBIC,要么仍然没有标准化,要么只是最近才 (↦
https://datatracker.ietf.org/doc/html/rfc8312)成为RFC.

第二个原因是NewReno是一个相对简单的设置。由于算法需要一些
调整来处理QUIC与TCP的差异,因此在更简单的算法上解释这些变
化更容易。因此,RFC 9002 应该更多地理解为“如何使拥塞控制算
法适应 QUIC”,而不是“这是你应该用于 QUIC 的东西”。事实上,
大多数生产级 QUIC 实现都对 Cubic (↦ https://blog.cloudflare.com/cubic-
and-hystart-support-in-quiche/) 和 BBR (↦
https://qlog.edm.uhasselt.be/epiq/files/QUICImplementationDiversity_Marx_final_11ju
n2020.pdf) 进行了自定义实现。

值得重申的是,拥塞控制算法不是特定于TCP或QUIC的;它们可以
被任何一种协议使用,并且希望QUIC的进步最终也会进入TCP堆
栈。

您知道吗?

请注意 拥塞控制旁边是 个称为流控制的 ( htt // f


请注意,拥塞控制旁边是一个称为流控制的 (↦ https://www.rfc-
editor.org/rfc/rfc9000.html#name-flow-control)相关概念。这两个功能在TCP
中经常被混淆,因为它们都被称为使用“TCP窗口”,尽管实际上有
两个窗口:拥塞窗口和TCP接收窗口。但是,对于我们感兴趣的网
页加载用例,流控制的作用要少得多,因此我们将在此处跳过它。
可提供更 (↦
https://qlog.edm.uhasselt.be/epiq/files/QUICImplementationDiversity_Marx_final_11ju
n2020.pdf)深入的信息 (↦ https://youtu.be/HQ1uIClmzkU?t=603)。 (↦
https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/)

这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN)

QUIC仍然受到物理定律的约束,并且需要对互联网上的其他发件人友好。这意
味着它不会比TCP更快地神奇地下载您的网站资源。然而,QUIC的灵活性意味
着尝试新的拥塞控制算法将变得更加容易,这应该会在未来改善TCP和QUIC的
情况。

0-RTT 连接设置# (↦ #0-Rtt-Connection-Set-Up)


第二个性能方面是关于在新连接上发送有用的 HTTP 数据(例如,页面资源)
之前需要多少次往返。有些人声称QUIC比TCP + TLS快两到三次往返,但我们会
看到它实际上只有一次。

您知道吗?

正如我们在第 1 部分中 (↦ https://www.smashingmagazine.com/2021/08/http3-


core-concepts-part1/)所说,在交换 HTTP 请求和响应之前,连接通常会
执行一次 (TCP) 或两次 (TCP + TLS) 握手。这些握手交换客户
端和服务器都需要知道的初始参数,以便例如加密数据。

正如您在下面的图 2 中看到的,每次握手至少需要一次往返才能完

成(TCP + TLS 1.3,(b)),有时需要两次(TLS 1.2 和之前的


( )) 这是低效的 因为我们至少需要两次来回的握手等待时
(a))。这是低效的,因为我们至少需要两次来回的握手等待时
间(开销)才能发送第一个HTTP请求,这意味着等待至少三次往
返,以便第一个HTTP响应数据(返回的红色箭头)进入。在慢速
网络上,这可能意味着 100 到 200 毫秒的开销。

(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/9f4c69d1-5ab6-
4ca2-ad1e-ec68d99dc9ab/connection-setup-1.png)

图 2:TCP + TLS 与 QUIC 连接设置。(大预览 (↦


https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/9f4c69d1-5ab6-
4ca2-ad1e-ec68d99dc9ab/connection-setup-1.png))

您可能想知道为什么TCP + TLS握手不能简单地组合在同一往返行程中完成。虽
然这在概念上是可能的(QUIC正是这样做的),但事情最初并不是这样设计
的,因为我们需要能够在顶部使用和带TLS的TCP (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#there-is-no-quic-without-
tls)。换句话说,TCP根本不支持在握手期间发送非TCP的东西。已经有人努力用
TCP快速开放扩展来添加它;但是,如第 1 部分 (↦

https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#quic-is-flexible-and-evolvable)
所述,事实证明,这很难大规模部署 (↦ https://squeeze.isobar.com/2019/04/11/the-sad-story-
of-tcp-fast-open)。
幸运的是,QUIC从一开始就考虑到了TLS,因此确实将传输和加密握手结合在
一个机制中。这意味着 QUIC 握手总共只需要一次往返行程即可完成,即比 TCP
+ TLS 1.3 少一次往返(参见上面的图 2c)。

您可能会感到困惑,因为您可能已经读到QUIC比TCP快两到三次往返,而不仅
仅是一次。这是因为大多数文章只考虑最坏的情况(TCP + TLS 1.2,(a)),
没有提到现代TCP + TLS 1.3也“仅”进行两次往返((b)很少显示)。虽然一次往
返的速度提升是不错的,但这并不令人惊叹。特别是在快速网络上(例如,小
于50毫秒的RTT),这几乎不会引起注意,尽管慢速网络和与远程服务器的连
接会更有利可图。

接下来,您可能想知道为什么我们需要等待握手。为什么我们不能在第一次往
返中发送 HTTP 请求?这主要是因为,如果我们这样做,那么第一个请求将在
未加密的情况下发送,并且可以被网络上的任何窃听者读取,这显然对隐私和
安全不是很好。因此,我们需要等待加密握手完成,然后再发送第一个 HTTP
请求。还是我们?

这是在实践中使用聪明技巧的地方。我们知道,用户经常在首次访问后的短时
间内重新访问网页。因此,我们可以使用初始加密连接在将来引导第二个连
接。简而言之,在其生存期内的某个时候,第一个连接用于在客户端和服务器
之间安全地传递新的加密参数。然后,这些参数可以从一开始就用于加密第二
个连接,而不必等待完整的 TLS 握手完成。这种方法称为“会话恢复”。

它允许强大的优化:我们现在可以安全地发送我们的第一个HTTP请求以及
QUIC / TLS握手,从而节省了另一个往返行程!至于TLS 1.3,这有效地消除了
TLS握手的等待时间。此方法通常称为 0-RTT(当然,HTTP 响应数据仍需要一
次往返才能开始到达)。

会话恢复和 0-RTT 都是我经常看到的被错误地解释为 QUIC 特定功能的东西。实


际上,这些实际上是TLS功能,这些功能已经在TLS 1.2中以某种形式存在,现在
在TLS 1.3 (↦ https://tools.ietf.org/html/rfc8446#section-2.3)中完全成熟。

换句话说,正如您在下面的图3中看到的那样,我们也可以获得这些功能相对于
TCP的性能优势(因此也可以获得HTTP / 2甚至HTTP / 1.1)的性能优势!我们看
到,即使使用0-RTT,QUIC仍然只比功能最佳的TCP + TLS 1.3堆栈快一个往返。

QUIC的往返行程快了三次的说法来自于比较图2的(a)和图3的(f),正如我
们所看到的,这并不公平。
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/ddbd604f-cec4-
4e61-9172-707eda88bc99/connection-setup-2.png)

图 3:TCP + TLS 与 QUIC 0-RTT 连接设置的对比。(大预览 (↦


https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/ddbd604f-cec4-
4e61-9172-707eda88bc99/connection-setup-2.png))

最糟糕的是,当使用0-RTT时,由于安全性,QUIC甚至无法真正很好地使用获
得的往返行程。要理解这一点,我们需要了解TCP握手存在的原因之一。首先,
它允许客户端在向服务器发送任何更高层数据之前,确保服务器在给定的IP地
址上实际上可用。

其次,在这里至关重要的是,它允许服务器确保打开连接的客户端实际上是他
们在发送数据之前所说的人以及在哪里。如果您还记得我们在第 1 部分中 (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#quic-supports-connection-
migration)如何定义与 4 元组的连接,您就会知道客户端主要由其 IP 地址标识。
这就是问题所在:IP地址可以被欺骗!

假设攻击者通过 QUIC 0-RTT 上的 HTTP 请求一个非常大的文件。但是,他们欺


骗了他们的IP地址,使其看起来像0-RTT请求来自受害者的计算机。如下图 4 所
示。QUIC 服务器无法检测 IP 是否被欺骗,因为这是它从该客户端看到的第一
个数据包。
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/64b9318e-3f18-
4852-b911-409033d8645b/amplification.png)

图 4:攻击者在向 QUIC 服务器发送 0-RTT 请求时,可以欺骗其 IP 地址,从而


触发对受害者的放大攻击。(大预览 (↦
https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/64b9318e-3f18-
4852-b911-409033d8645b/amplification.png))

如果服务器只是开始将大文件发送回欺骗性IP,它最终可能会使受害者的网络
带宽过载(特别是如果攻击者并行执行许多此类虚假请求)。请注意,受害者

会丢弃QUIC响应,因为它不需要传入的数据,但这并不重要:他们的网络仍然
这被称为反射或放大攻击 (↦ https://www.f5.com/labs/articles/education/what-is-a-dns-
需要处理数据包!
amplification-attack-),这是黑客执行分布式拒绝服务(DDoS)攻击的重要方式。请
注意,当使用基于 TCP + TLS 的 0-RTT 时,不会发生这种情况,正是因为 TCP
握手需要先完成,然后才能将 0-RTT 请求与 TLS 握手一起发送。

因此,QUIC在回复0-RTT请求时必须保守,限制它发送的数据量,直到客户端
被验证为真正的客户端而不是受害者。对于 QUIC,此数据量已设置为从客户端
接收的量的三倍 (↦ https://www.rfc-editor.org/rfc/rfc9000.html#name-address-validation)。

换句话说 的最大 放大因子 为 这被确定为性能有用性和安全风险之间


换句话说,QUIC的最大“放大因子”为3,这被确定为性能有用性和安全风险之间
的可接受权衡(特别是与一些放大因子超过51,000倍 (↦
https://www.cloudflare.com/learning/ddos/memcached-ddos-attack/)的事件相比)。由于客户
端通常首先只发送一到两个数据包,因此QUIC服务器的0-RTT回复的上限仅为4
到6 KB(包括其他QUIC和TLS开销!),这有点令人印象深刻。

此外,其他安全问题可能导致,例如,“重放攻击”,这限制了您可以执行的
HTTP请求的类型。例如,Cloudflare 只允许在 0-RTT 中没有查询参数的 HTTP
GET 请求 (↦ https://blog.cloudflare.com/introducing-0-rtt/#whatsthecatch)。这些进一步限制
了0-RTT的实用性。

幸运的是,QUIC可以选择让它变得更好一点。例如,服务器可以检查 0-RTT 是
否来自以前与之具有有效连接的 IP (↦ https://www.rfc-editor.org/rfc/rfc9000.html#name-
address-validation-for-futu)。但是,仅当客户端保持在同一网络上时,这才有效(这
在一定程度上限制了QUIC的连接迁移 (↦ #connection-migration)功能)。即使它有
效,QUIC的响应仍然受到我们上面 (↦ #congestion-control)讨论的拥塞控制器的慢启
动逻辑的限制;因此,除了节省的一次往返行程外,没有额外的速度提升。

您知道吗?

有趣的是,QUIC的三倍放大限值也适用于图2c中正常的非0-RTT握
手过程。例如,如果服务器的 TLS 证书 (↦ https://hpbn.co/transport-layer-
security-tls/#chain-of-trust-and-certificate-authorities)太大而无法容纳在 4 到 6
KB 内,则可能会出现问题。在这种情况下,它必须被拆分,第二
个块必须等待第二个往返行程被发送(在确认前几个数据包之后,
表明客户端的IP没有被欺骗)。在这种情况下,QUIC的握手可能

最终仍然需要两次往返,等于TCP + TLS!这就是为什么对于QUIC
来说,证书压缩 (↦ https://www.fastly.com/blog/quic-handshake-tls-compression-
certificates-extension-study)等技术将格外重要。

您知道吗?

可能是某些高级设置能够缓解这些问题,使0-RTT更有用。例如,
服务器可以记住客户端在上次看到时有多少可用带宽,从而减少其
受拥塞控制重新连接(非欺骗性)客户端的缓慢启动的限制 这在
受拥塞控制重新连接(非欺骗性)客户端的缓慢启动的限制。这在
学术界已经进行了调查 (↦ https://arxiv.org/pdf/1905.03144.pdf),甚至在
QUIC中提出了一个扩展 (↦ https://tools.ietf.org/html/draft-kuhn-quic-0rtt-bdp-
08)来做到这一点。一些公司已经这样做了,以加快TCP的速度。

另一种选择是让客户端发送一个或两个以上的数据包(例如,发送
7 个带有填充的数据包),因此三倍限制转换为更有趣的 12 到 14
KB 响应,即使在连接迁移之后也是如此。我已经在我的一篇论文
中 (↦
https://qlog.edm.uhasselt.be/epiq/files/QUICImplementationDiversity_Marx_final_11ju
n2020.pdf)写过这个问题。

最后,(行为不端)QUIC服务器也可以故意增加三倍的限制,如
果他们觉得这样做是安全的,或者如果他们不关心潜在的安全问题
(毕竟,没有协议警察 (↦ https://tools.ietf.org/html/rfc8962)阻止这种情
况)。

这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN-1)

QUIC使用0-RTT进行更快的连接设置实际上更像是一种微优化,而不是革命性
的新功能。与最先进的TCP + TLS 1.3设置相比,它最多可以节省一次往返。在第
一次往返行程中实际可以发送的数据量还受到许多安全注意事项的限制。

因此,如果您的用户位于延迟非常高的网络(例如,RTT超过200毫秒的卫星网
络)上,或者您通常不会发送太多数据,则此功能将大放异彩。后者的一些例
子是大量缓存的网站,以及通过API和其他协议(如DNS-over-QUIC (↦
https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic))定期获取小更新的单页应用
程序。Google看到QUIC的0-RTT结果非常好 (↦ https://storage.googleapis.com/pub-tools-
public-publication-data/pdf/8b935debf13bd176a08326738f5f88ad115a071e.pdf)的原因之一是,它
在已经高度优化的搜索页面上对其进行了测试,其中查询响应非常小。

在其他情况下,您最多只能获得几十毫秒,如果您已经在使用CDN,则更少
(如果您关心性能,则应这样做!

连接迁移# (↦ #Connection-Migration)
连接迁移# (↦ #Connection-Migration)

第三个性能特性通过保持现有连接不变,使 QUIC 在网络之间传输时更快。虽


然这确实有效,但这种类型的网络更改并不经常发生,并且连接仍然需要重置
其发送速率。

如第 1 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1#quic-
supports-connection-migration)所述,QUIC 的连接 ID (CID) 允许它在切换网络时执
行连接迁移。我们通过客户端从Wi-Fi网络移动到4G来说明这一点,同时进行大
文件下载。在 TCP 上,该下载可能必须中止,而对于 QUIC,它可能会继续。

但是,首先要考虑这种类型的场景实际发生的频率。您可能会认为,在建筑物
内的 Wi-Fi 接入点之间移动或在路上的蜂窝塔之间移动时,也会发生这种情况。
但是,在这些设置中(如果正确完成),您的设备通常会保持其IP不变,因为
无线基站之间的转换是在较低的协议层完成的。因此,只有当你在完全不同的
网络之间移动时,它才会发生,我想说这并不经常发生。

其次,我们可以问这是否也适用于除大文件下载以及实时视频会议和流媒体之
外的其他用例。如果您在切换网络的确切时刻加载网页,则可能确实需要重新
请求一些(稍后的)资源。

但是,加载页面通常需要几秒钟,因此与网络交换机重合也不会很常见。此
外,对于这是一个紧迫问题的用例,其他缓解措施通常已经到位。例如,提供
大型文件下载的服务器可以支持 HTTP 范围请求 (↦ https://developer.mozilla.org/en-
US/docs/Web/HTTP/Range_requests)以允许可恢复下载。

由于网络 1 下降和网络 2 可用之间通常存在一些重叠时间,因此视频应用可以打


开多个连接(每个网络 1 个),在旧网络完全消失之前同步它们。用户仍会注意
到该开关,但它不会完全丢弃视频源。

第三,不能保证新网络将具有与旧网络一样多的可用带宽。因此,即使概念连
接保持不变,QUIC服务器也不能继续高速发送数据。相反,为了避免新网络过
载,它需要重置(或至少降低)发送速率,并在拥塞控制器的慢启动阶段再次
启动 (↦ #congestion-control)。

由于此初始发送速率通常太低,无法真正支持诸如视频流之类的内容,因此即
使在QUIC上,您也会看到一些质量损失或打嗝。从某种意义上说,连接迁移更
多的是防止连接上下文在服务器上发生改动和开销,而不是提高性能。

您知道吗?
您知道吗?

请注意,正如上面针对 0-RTT 所讨论的,我们可以设计一些高级技


术来改进连接迁移。例如,我们可以再次尝试记住上次给定网络上
有多少带宽可用,并尝试更快地提升到该级别以进行新的迁移。此
外,我们可以设想的不仅仅是在网络之间切换,而是同时使用两
者。这个概念称为多路径,我们将在下面更详细地讨论它 (↦ #future-
developments-to-look-out-for)。

到目前为止,我们主要讨论了主动连接迁移,即用户在不同网络之间移动。但
是,也存在被动连接迁移 (↦ https://www.rfc-editor.org/rfc/rfc9000.html#name-connection-
migration)的情况,其中某个网络本身会更改参数。这方面的一个很好的例子是网
络地址转换 (↦ https://computer.howstuffworks.com/nat.htm) (NAT) 重新绑定。虽然
NAT 的完整讨论超出了本文的范围,但它主要意味着连接端口号可以在任何给
定时间更改,而不会发出警告。在大多数路由器中,UDP 也比 TCP 更频繁地发
生这种情况。

如果发生这种情况,QUIC CID 将不会更改,并且大多数实现将假定用户仍位于


同一物理网络上,因此不会重置拥塞窗口或其他参数。QUIC 还包括一些功能,
如 PING (↦ https://www.rfc-editor.org/rfc/rfc9000.html#frame-ping) 和超时指示器 (↦
https://www.rfc-editor.org/rfc/rfc9000.html#idle-timeout),以防止这种情况发生,因为这通
常发生在长时间空闲的连接中。

我们在第 1 部分中 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-


part1/#quic-supports-connection-migration)讨论过,出于安全原因,QUIC 不仅使用单个
CID。相反,它会在执行活动迁移时更改 CID。在实践中,它甚至更复杂,因为
客户端和服务器都有单独的CID列表(在QUIC RFC中称为源和目标CID (↦
https://www.rfc-editor.org/rfc/rfc9000.html#name-connection-id))。下文图 5 对此进行了说
明。
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/6a0b9339-6976-
458d-afc2-4a0cb97a7291/4-migration-src-dst-cid.png)

图 5:QUIC 使用单独的客户端和服务器 CID。(大预览 (↦


https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/6a0b9339-6976-
458d-afc2-4a0cb97a7291/4-migration-src-dst-cid.png))

这样做是为了允许每个端点选择自己的CID格式和内容,这反过来又对于允许
高级路由和负载平衡逻辑至关重要。通过连接迁移,负载均衡器不能再只查看 4
元组来标识连接并将其发送到正确的后端服务器。但是,如果所有 QUIC 连接都
使用随机 CID,这将大大增加负载平衡器的内存要求,因为它需要存储到后端
服务器的 CID 映射。此外,这仍然不适用于连接迁移,因为 CID 更改为新的随
机值。

因此,部署在负载平衡器后面的 QUIC 后端服务器必须具有其 CID 的可预测格


式,以便负载平衡器可以从 CID 派生正确的后端服务器,即使在迁移之后也是
如此。IETF的拟议文档中描述了执行此操作的一 (↦
https://datatracker.ietf.org/doc/html/draft-ietf-quic-load-balancers-06)些选项。为了实现这一
切,服务器需要能够选择自己的CID,如果连接发起人(对于QUIC来说,它始
终是客户端)选择CID,这是不可能的。这就是 QUIC 中客户端和服务器 CID 之
间存在拆分的原因。

这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN-2)

因此,连接迁移是一种情境特征。例如,谷歌的初步测试 (↦
https://github.com/quicwg/wg-
materials/blob/main/ietf104/IETF_104_QUIC_Connection_Migration.pdf)显示,其用例的改进百
分比很低。许多 QUIC 实现尚未实现此功能。即使那些这样做的人通常也会将其
限制为移动客户端和应用程序,而不是其桌面等效项。有些人甚至认为不需要
该功能,因为在大多数情况下,使用 0-RTT 打开新连接应该具有类似的性能属

性。

尽管如此,根据您的使用案例或用户配置文件,它可能会产生很大的影响。如
果您的网站或应用程序最常在移动中使用(例如,像Uber或Google Maps这样的
东西),那么与用户通常坐在办公桌后面相比,您可能会受益更多。同样,如
果你专注于持续的互动(无论是视频聊天,协作编辑还是游戏),那么你最坏
的情况应该比你有一个新闻网站更有改善。

线头阻塞移除# (↦ #Head-Of-Line-Blocking-Removal)

第四个性能功能旨在通过缓解线头 (HoL) 阻塞问题,在数据包丢失量大的网


络上使 QUIC 更快。虽然这在理论上是正确的,但我们将看到在实践中,这可能
只会为网页加载性能提供一些小好处。

但是,要理解这一点,我们首先需要绕道而行,讨论流优先级和多路复用。

流优先级# (↦ #STREAM-PRIORITIZATION)

如第 1 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#why-do-we-
need-http-3)所述,单个 TCP 数据包丢失可能会延迟多个传输中资源的数据,因为
TCP 的字节流抽象将所有数据视为单个文件的一部分。另一方面,QUIC非常清
楚存在多个并发字节流,并且可以基于每个流处理损失。但是,正如我们也看
到的那样,这些流并没有真正并行传输数据:相反,流数据被多路复用到单个
连接上。这种多路复用可以通过许多不同的方式发生。

例如,对于流 A、B 和 C,我们可能会看到一个数据包序列 ,其中我们更改每个


数据包中的活动流(我们称之为轮循机制)。但是,我们还可能看到 相反的模
式,其中每个流在开始下一个流之前完整完成(让我们称之为顺序)。当然,
在这些极端(, , 等)之间还有许多其他选择。多路复用方案是动态的,由称
为流优先级的 HTTP 级功能驱动(本文稍后将讨论 (↦ #stream-prioritization))。
ABCABCABCABCABCABCABCABC AAAAAAAABBBBBBBBCCCCCCCC AAAABBCAAAAABBC… AABBCCAABBCC…
ABABABCCCC…

事实证明,您选择的多路复用方案会对网站加载性能产生巨大影响。您可以在
下面的视频中看到这一点,由Cloudflare (↦ https://blog.cloudflare.com/better-http-2-
prioritization-for-a-faster-web/)提供,因为每个浏览器都使用不同的多路复用器。原因
相当复杂,我已经写了几 (↦
https://speeder.edm.uhasselt.be/www18/files/h2priorities_mwijnants_www2018.pdf)篇关于这个主
题的学术论文 (↦
https://h3.edm.uhasselt.be/files/ResourceMultiplexing_H2andH3_Marx2020.pdf),并在一次会议上
谈到了它 (↦ https://www.youtube.com/watch?v=nH4iRpFnf1c)。Patrick Meenan,Pagetest
(↦ https://www.webpagetest.org/)的名声,甚至有一个关于这个主题的三个小时的教程
(↦ https://www.youtube.com/watch?v=ct5MvtmL1NM)。

(↦ https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/)

流多路复用差异可能会对不同浏览器中的网站加载产生重大影响。(大预览
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/6a0b9339-
6976-458d-afc2-4a0cb97a7291/4-migration-src-dst-cid.png))

幸运的是,我们可以相对容易地解释基础知识。如您所知,某些资源可能会呈
现阻塞 (↦ https://web.dev/render-blocking-resources/)。CSS文件和HTML元素中的某些
JavaScript就是这种情况。当这些文件正在加载时,浏览器无法绘制页面(或
者,例如,执行新的JavaScript)。 head

更重要的是,CSS和JavaScript文件需要完整下载才能使用(尽管它们通常可以
增量解析和编译)。因此,需要以最高优先级尽快加载这些资源。让我们考虑
一下,如果 A、B 和 C 都是渲染阻塞资源,会发生什么情况。
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/46ae54c1-2985-
4c47-9ebe-18686bbfc4ce/multiplexing-render-blocking.png)

图 6:流多路复用方法会影响(渲染阻塞)资源完成时间。(大预览 (↦
https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/46ae54c1-2985-
4c47-9ebe-18686bbfc4ce/multiplexing-render-blocking.png))

如果我们使用轮循机制多路复用器(图 6 中的顶行),我们实际上会延迟每个
资源的总完成时间,因为它们都需要与其他资源共享带宽。由于我们只能在它
们完全加载后使用它们,因此这会导致明显的延迟。但是,如果我们按顺序多
路复用它们(图 6 中的最下面一行),我们会看到 A 和 B 完成得更早(并且可
以由浏览器使用),而实际上并没有延迟 C 的完成时间。

但是,这并不意味着顺序多路复用总是最好的,因为一些(主要是非渲染阻
塞)资源(如HTML和渐进式JPEG)实际上可以增量处理和使用。在这些(以
及其他一些)情况下,使用第一个选项(或至少介于两者之间)是有意义的。

尽管如此,对于大多数网页资源来说,事实证明顺序多路复用性能最佳。例
如,这就是谷歌浏览器在上面的视频中正在做的事情,而Internet Explorer正在
使用最坏情况的循环多路复用器。

数据包丢失弹性# (↦ #PACKET-LOSS-RESILIENCE)

现在我们知道所有流并不总是同时处于活动状态,并且它们可以以不同的方式
多路复用,我们可以考虑如果数据包丢失会发生什么。如第 1 部分 (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#why-do-we-need-http-3)所
述,如果一个 QUIC 流遇到数据包丢失,则仍然可以使用其他活动流(而在 TCP
中,所有活动流都将暂停)。

但是,正如我们刚刚看到的,拥有许多并发活动流通常不是Web性能的最佳选
择,因为它可以延迟一些关键(渲染阻塞)资源,即使没有数据包丢失!我们
宁愿使用顺序多路复用器同时只有一两个处于活动状态。但是,这减少了QUIC
的HoL阻塞删除的影响。

例如,假设发送方可以在给定时间传输 12 个数据包(请参阅下面的图 7)— 请


记住,这受拥塞控制器 (↦ #congestion-control)的限制)。如果我们用流 A 的数据填
充所有 12 个数据包(因为它是高优先级和渲染阻塞 — 想想),那么我们在 12 个
数据包窗口中将只有一个活动流。 main.js

如果其中一个数据包丢失,那么QUIC最终仍将完全被HoL阻止,因为除了以下
之外,根本没有其他可以处理的流:所有数据都是用于,因此所有内容仍然需
要等待(我们没有或数据要处理),类似于TCP。 A A B C

(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/05412377-b92f-
4adc-9725-4a3b4b4d602a/hol-blocking-rr-sequential.png)

图 7:数据包丢失影响取决于所使用的多路复用器。(请注意,我们假设每
个流要发送的数据比前面的类似图像中更多。(大预览 (↦
https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/05412377-b92f-
4adc-9725-4a3b4b4d602a/hol-blocking-rr-sequential.png))

我们看到我们有一种矛盾:顺序多路复用()通常更适合Web性能,但它不允
许我们充分利用QUIC的HoL阻塞删除。循环多路复用()对HoL阻止更好,但
对Web性能更差。因此,一个最佳实践或优化最终可能会撤消另一个最佳实践
或优化。 AAAABBBBCCCC ABCABCABCABC

而且情况变得更糟。到目前为止,我们一直假设单个数据包一次丢失一个。但
是,这并不总是正确的,因为互联网上的数据包丢失通常是“突发的” (↦
https://huitema.wordpress.com/2020/07/12/parsing-quic-logs-and-assessing-packet-losses/),这意味
着多个数据包经常同时丢失。

如上所述 (↦ #congestion-control),数据包丢失的一个重要原因是网络过载了太多数
据,不得不丢弃多余的数据包。这就是拥塞控制器开始缓慢发送的原因。但
是,它随后不断增长其发送速率,直到...有丢包!
换句话说,旨在防止网络过载的机制实际上使网络过载(尽管是以受控方
式)。在大多数网络上,当发送速率增加到每次往返数百个数据包时,这种情
况会在相当长的一段时间后发生。当它们达到网络的极限时,它们中的几个通
常会一起丢弃,从而导致突发损失模式。

您知道吗?

这就是为什么我们希望将单个(TCP)连接与HTTP / 2一起使用,
而不是与HTTP / 1.1的6到30个连接的原因之一。由于每个单独的连
接都以几乎相同的方式提高了其发送速率,因此HTTP / 1.1可以在开
始时获得良好的速度,但是连接实际上可能会开始导致彼此的大量
数据包丢失,因为它们会导致网络变得过载。

当时,Chromium开发人员推测 (↦ https://a77db9aa-a-7b23c8ea-s-
sites.googlegroups.com/a/chromium.org/dev/spdy/An_Argument_For_Changing_TCP_S
low_Start.pdf),这种行为导致了互联网上看到的大部分数据包丢失。
这也是BBR成为一种常用的拥塞控制算法的原因之一,因为它使用
观察到的RTT的波动而不是数据包丢失来评估可用带宽。

您知道吗?

数据包丢失的其他原因可能导致丢失(或不可用)的数据包更少或
单个,尤其是在无线网络上。然而,在那里,损失通常在较低的协
议层检测到,并在两个本地实体(例如智能手机和4G蜂窝塔)之
间解决,而不是通过客户端和服务器之间的重新传输来解决。这些
通常不会导致真正的端到端数据包丢失,而是显示为数据包延迟
(或“抖动”)和重新排序的数据包到达的变化。

因此,假设我们正在使用每数据包轮循机制多路复用器()来充分利用HoL阻塞
删除,并且我们只获得了4个数据包的突发丢失。我们看到这将始终影响所有 3
个流(请参阅图 8,中间行)!在这种情况下,QUIC的HoL阻塞删除没有任何
好处,因为所有流都必须等待自己的重传。 ABCABCABCABCABCABCABCABC…
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/93cb3e10-16dd-
4647-af85-91cc723d35f6/hol-blocking-bursty.png)

图 8:根据所使用的多路复用器和数据包丢失模式,受影响的流越多或越
少。(大预览 (↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-
46f01eedd629/93cb3e10-16dd-4647-af85-91cc723d35f6/hol-blocking-bursty.png))

为了降低多个流受到有损突发影响的风险,我们需要为每个流连接更多数据。
例如,是一个小的改进,并且(参见上面图 8 中的底行)甚至更好。您可以再
次看到,顺序更进一步的方法更好,即使这样可以减少我们有多个并发活动流
的机会。 AABBCCAABBCCAABBCCAABBCC… AAAABBBBCCCCAAAABBBBCCCC…

最后,预测QUIC的HoL阻塞删除的实际影响是困难的,因为它取决于流的数
量,丢失突发的大小和频率,流数据的实际使用方式等。但是,目前的大多数
结果表明 (↦ https://h3.edm.uhasselt.be/files/ResourceMultiplexing_H2andH3_Marx2020.pdf),它
对网页加载的用例没有多大帮助,因为我们通常需要更少的并发流。
如果您想了解有关此主题的更多详细信息或只是一些具体示例,请查看我关于
HTTP HoL阻止的深入文章 (↦ https://calendar.perfplanet.com/2020/head-of-line-blocking-in-
quic-and-http-3-the-details/)。

您知道吗?

与前面的部分一样,一些高级技术可以在这里帮助我们。例如,现
代拥塞控制器使用数据包步调 (↦
https://homes.cs.washington.edu/~tom/pubs/pacing.pdf)。这意味着它们不会在
单个突发中发送100个数据包,而是将它们分散在整个RTT上。从
概念上讲 这降低 络过载的机会 恢复 烈建议使
概念上讲,这降低了网络过载的机会,QUIC恢复RFC强烈建议使用
它 (↦ https://www.rfc-editor.org/rfc/rfc9002.html#name-pacing)。作为补充,一
些拥塞控制算法(如BBR (↦ https://blog.apnic.net/2017/05/09/bbr-new-kid-tcp-
block/))不会不断提高其发送速率,直到它们导致数据包丢失,而
是在此之前退缩(例如,通过查看RTT波动,因为当网络过载时
RTT也会上升)。

虽然这些方法降低了数据包丢失的总体几率,但它们并不一定能降
低其突发性。

这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN-3)

虽然QUIC的HoL阻塞删除在理论上意味着它(和HTTP / 3)应该在有损网络上表
现更好,但在实践中,这取决于很多因素。由于网页加载的用例通常倾向于更
连续的多路复用设置,并且由于数据包丢失是不可预测的,因此此功能可能主
要影响最慢的1%的用户。然而,这仍然是一个非常活跃的研究领域,只有时间
会证明一切。

尽管如此,在某些情况下可能会看到更多的改进。这些大多超出了第一个满页
加载的典型用例 - 例如,当资源不呈现阻塞时,当它们可以增量处理时,当流完
全独立时,或者当同时发送的数据较少时。

示例包括缓存良好的页面上的重复访问,以及单页应用中的后台下载和 API 调
用。例如,Facebook已经看到了在使用HTTP / 3在其本机应用程序中加载数据时
HoL阻止删除的一些好处。

UDP 和 TLS 性能# (↦ #Udp-And-Tls-Performance)


QUIC 和 HTTP/3 的第五个性能方面是关于它们在网络上实际创建和发送数据包
的效率和性能。我们将看到QUIC对UDP和重加密的使用可以使其比TCP慢一些
(但情况正在改善)。

首先,我们已经讨论过 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-
part1/#why-do-we-need-http-3),QUIC对UDP的使用更多的是关于灵活性和可部署性,
而不是关于性能。直到最近,通过UDP发送QUIC数据包通常比发送TCP数据包
慢得多 这 事实更证明了这 点 这部分是因为这些协议通常在何处以及如
慢得多,这一事实更证明了这一点。这部分是因为这些协议通常在何处以及如
何实现(请参阅下面的图9)。

(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/cffc7945-bd57-
459f-b6d3-ed06f51b30ad/kernel-user-space.png)

图 9:TCP 和 QUIC 之间的实现差异。(大预览 (↦


https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/cffc7945-bd57-
459f-b6d3-ed06f51b30ad/kernel-user-space.png))

如上所述 (↦ #congestion-control),TCP和UDP通常直接在操作系统的快速内核中实
现。相比之下,TLS和QUIC实现大多位于较慢的用户空间中(请注意,QUIC并
不需要这样做 - 它主要是因为它更灵活)。这使得QUIC已经比TCP慢了一点。

此外,当从我们的用户空间软件(例如,浏览器和Web服务器)发送数据时,
我们需要将此数据传递给操作系统内核,然后操作系统内核使用TCP或UDP将
其实际放在网络上。传递此数据是使用内核 API(系统调用)完成的,这涉及每
个 API 调用的一定数量的开销。对于 TCP,这些开销远低于 UDP。

这主要是因为从历史上看,TCP的使用比UDP多得多。因此,随着时间的推移,
TCP 实现和内核 API 中添加了许多优化,以将数据包发送和接收开销降至最
低。许多网络接口控制器 (NIC) 甚至具有 TCP 的内置硬件卸载功能。然而,
UDP就没有那么幸运了,因为它的使用更有限,并不能证明在增加优化方面的
投资是合理的。在过去的五年中,这种情况很幸运地发生了变化,大多数操作
系统也为UDP添加了优化选项 (↦ https://blog.cloudflare.com/how-to-receive-a-
million-packets/)。

其次,QUIC有很多开销,因为它单独加密每个数据包。这比在 TCP 上使用 TLS


要慢,因为在那里您可以按块加密数据包 (↦ https://blog.cloudflare.com/optimizing-tls-
over-tcp-to-reduce-latency/)(一次最多约 16 KB 或 11 个数据包),这样效率更高。这
是QUIC中有意识的权衡,因为批量加密可能导致其自身形式的HoL阻止 (↦
https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/)。

与第一点不同,我们可以添加额外的API来使UDP(以及QUIC)更快,在这里,
QUIC总是对TCP + TLS具有固有的缺点。但是,这在实践中也是非常可管理的,
例如,优化的加密库 (↦ https://github.com/h2o/picotls/pull/310)和允许批量加密QUIC数据
包标头的聪明方法。

因此,虽然谷歌最早的QUIC版本仍然是TCP + TLS的两倍 (↦
https://rjshade.com/work/files/papers/pdf/langley_et_al_sigcomm2017_quic.pdf),但自那以后,情
况肯定有所改善。例如,在最近的测试中,微软高度优化的QUIC堆栈 (↦
https://github.com/microsoft/msquic)能够获得7.85 Gbps,而在同一系统上的TCP + TLS为
11.85 Gbps(所以在这里,QUIC的速度大约是TCP + TLS的66%)。

这是最近的Windows更新,这使得UDP更快(为了进行全面比较,该系统上的

UDP吞吐量为19.5 Gbps)。谷歌QUIC堆栈最优化的版本目前比TCP + TLS慢约


20% (↦ https://youtu.be/xxN4FfwaANk?t=3161)。Fastly (↦ https://www.fastly.com/blog/measuring-
quic-vs-tcp-computational-efficiency)在不太先进的系统上的早期测试,以及一些技巧甚
至声称具有相同的性能(约450 Mbps),这表明根据用例,QUIC绝对可以与
TCP竞争。

但是,即使QUIC的速度是TCP + TLS的两倍,它也不是那么糟糕。首先,QUIC
和TCP + TLS处理通常不是服务器上发生的最重的事情,因为其他逻辑(例如,
HTTP,缓存,代理等)也需要执行。因此,您实际上并不需要两倍数量的服务
器来运行QUIC(不过,目前还不清楚它会对真正的数据中心产生多大的影响,
因为没有一家大公司发布这方面的数据)。

其次,未来仍然有很多机会优化QUIC实现。例如,随着时间的推移,一些QUIC
实现将(部分)移动到操作系统内核(很像TCP)或绕过它(有些已经这样做
了,如MsQuic (↦ https://github.com/microsoft/msquic)和Quant (↦
https://github.com/NTAP/quant))。我们还可以预期QUIC特定的硬件 (↦
https://datatracker.ietf.org/meeting/104/materials/slides-104-quic-offloading-quic-00)将可用。

尽管如此,在某些用例中,TCP + TLS仍将是首选选项。例如,Netflix 表示它可


尽管如 ,在某 用例中, 仍将是首选选项。例如, 表 可
能不会很快迁移到 QUIC,因为它在自定义 FreeBSD 设置上投入了大量资金 (↦
https://www.youtube.com/watch?v=8NSzkYSX5nY),以通过 TCP + TLS 流式传输其视频。

同样,Facebook表示,QUIC可能主要用于最终用户和CDN的边缘之间,但不会
用于数据中心之间或边缘节点与源站服务器之间,因为它的开销更大。一般来
说,非常高带宽的场景可能会继续有利于TCP + TLS,特别是在未来几年。

您知道吗?

优化网络堆栈是一个深而技术性的兔子洞,上面的内容只是触及了
表面(并且错过了很多细微差别)。如果你足够勇敢,或者你想知
道 像GRO / GSO , SO_TXTIME ,kernel bypass, sendmmsg() 和
revmmsg() 这样的术语是什么意思,我可以推荐一些关于
Cloudflare (↦ https://blog.cloudflare.com/accelerating-udp-packet-transmission-for-
quic/)和Fastly (↦ https://www.fastly.com/blog/measuring-quic-vs-tcp-computational-
efficiency)优化QUIC的优秀文章,以及Microsoft的广泛代码演练 (↦
https://www.youtube.com/watch?v=Icskyw17Dgw),以及思科 (↦

https://archive.fosdem.org/2020/schedule/event/fast_quic_sockets_for_cloud_networkin
g/)的深入演讲。最后,一位Google工程师发表了一个非常有趣的主
题演讲,内容是关于随着时间的推移优化他们的QUIC实现 (↦
https://www.youtube.com/watch?v=xxN4FfwaANk)。

这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN-4)

QUIC对UDP和TLS协议的特殊使用历来使其比TCP + TLS慢得多。但是,随着时
间的推移,已经取得了一些改进(并将继续实施),并在一定程度上缩小了差
距。但是,在网页加载的典型用例中,您可能不会注意到这些差异,但是如果
您维护大型服务器场,它们可能会让您头疼。

HTTP/3 特性# (↦ #Http-3-Features)

到目前为止,我们主要讨论了QUIC与TCP中的新性能特性。但是,HTTP/3 与
HTTP/2 呢?如第 1 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-
h d dh )所述 / 实际上是 / Q C 因此
part1/#why-do-we-need-http-3)所述,HTTP/3 实际上是 HTTP/2-over-QUIC,因此,
新版本中没有引入真正的、大的新功能。这与从HTTP / 1.1到HTTP / 2的转变不
同,HTTP / 2要大得多,并引入了标头压缩,流优先级和服务器推送等新功能。
这些功能仍然在HTTP / 3中,但是在引擎盖下如何实现它们方面存在一些重要的
差异。

这主要是因为QUIC如何消除HoL阻塞的工作原理。正如我们已经讨论过的 (↦
#head-of-line-blocking-removal),流 B 上的丢失不再意味着流 A 和 C 将不得不等待 B 的
重新传输,就像它们在 TCP 上所做的那样。因此,如果 A、B 和 C 都按该顺序发
送一个 QUIC 数据包,则它们的数据很可能会作为 A、C、B!换句话说,与TCP
不同,QUIC不再在不同的流中完全排序!

这是HTTP / 2的一个问题,它实际上依赖于TCP在其许多功能的设计中的严格排
序,这些功能使用特殊的控制消息穿插数据块。在QUIC中,这些控制消息可能
以任何顺序到达(并应用),甚至可能使功能与预期相反!同样,对于本文来
说,技术细节是不必要的,但是本文的前半部分 (↦
https://h3.edm.uhasselt.be/files/HTTP3_Prioritization_extended_3jul2019.pdf)应该可以让您了解这
可能变得多么愚蠢。

因此,对于HTTP / 3,这些功能的内部机制和实现必须进行更改。一个具体的例

子是HTTP标头压缩,它降低了重复的大型HTTP标头(例如,cookie和用户代
理字符串)的开销。在HTTP / 2中,这是使用HPACK (↦
https://datatracker.ietf.org/doc/html/rfc7541)设置完成的,而对于HTTP / 3,这已被重新设
计为更复杂的QPACK (↦ https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack)。这两个系
统提供相同的功能(即标头压缩),但方式完全不同。关于这个主题的一些优
秀的深入技术讨论和图表可以在Litespeed博客 (↦ https://blog.litespeedtech.com/tag/quic-
header-compression-design-team/)上找到。

对于驱动流多路复用逻辑的优先级功能也是如此,我们在上面已经简要讨论过
(↦ #head-of-line-blocking-removal)。在HTTP / 2中,这是使用复杂的“依赖关系树”设置
实现的,该设置明确尝试对所有页面资源及其相互关系进行建模(更多信息请
参阅“HTTP资源优先级的终极指南 (↦ https://www.youtube.com/watch?
v=nH4iRpFnf1c)”)。直接通过 QUIC 使用此系统会导致一些可能非常错误的树布
局,因为将每个资源添加到树中将是一个单独的控制消息。

此外,这种方法被证明是不必要的复杂,导致许多实现错误和效率低下 (↦
https://blog.cloudflare.com/nginx-structural-enhancements-for-http-2-performance/),并且在许多
服务器上的性能低于标准 (↦ https://github.com/andydavies/http2-prioritization-issues)。这两
致 级 统 单 方式 行 新
个问题都导致优先级系统以更简单的方式针对HTTP / 3进行了重新设计 (↦
https://blog.cloudflare.com/adopting-a-new-approach-to-http-prioritization/)。这种更直接的设置
使得某些高级方案难以或无法实施(例如,在单个连接上代理来自多个客户端
的流量),但仍支持广泛的网页加载优化选项。

虽然这两种方法同样提供了相同的基本功能(引导流多路复用),但希望HTTP
/ 3的设置更容易,从而减少实现错误。

最后,还有服务器推送。此功能允许服务器发送 HTTP 响应,而无需等待对它


们的显式请求。从理论上讲,这可以带来出色的性能提升。然而,在实践中,
它很难正确使用 (↦ https://calendar.perfplanet.com/2016/http2-push-the-details/)并且实施不一
致 (↦ https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/)。因此,它甚至可能将
从Google Chrome中删除 (↦ https://groups.google.com/a/chromium.org/g/blink-
dev/c/K3rYLvmQUBY/m/vOWBKZGoAQAJ)。

尽管如此,它仍然被定义为HTTP / 3中的一个功能 (↦
https://datatracker.ietf.org/doc/html/draft-ietf-quic-http)(尽管很少有实现支持它)。虽然它
的内部工作原理没有像前两个功能那样改变,但它也已经适应了QUIC的非确定
性排序。然而,可悲的是,这对解决一些长期存在的问题几乎没有帮助。

这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN-5)

正如我们之前所说,HTTP/3的大部分潜力来自底层的QUIC,而不是HTTP/3本
身。虽然该协议的内部实现与HTTP / 2有很大不同,但其高级性能特性以及它们
可以和应该如何使用它们保持不变。

值得关注的未来发展# (↦ #Future-Developments-To-Look-
Out-For)

在本系列中,我经常强调更快的演进和更高的灵活性是QUIC的核心方面(以及
扩展的HTTP / 3)。因此,人们已经在研究协议的新扩展和应用也就不足为奇
了。下面列出的是您可能会在某个地方遇到的主要问题:

前向纠错 (↦ https://tools.ietf.org/html/draft-swett-nwcrg-coding-for-quic)

此技术的目的再次是提高 QUIC 对数据包丢失的恢复能力。它通过发送数


据的冗余副本来实现此目的(尽管经过巧妙的编码和压缩,使它们不那么
大) 然后 如果数据包丢失但冗余数据到达 则不再需要重新传输
大)。然后,如果数据包丢失但冗余数据到达,则不再需要重新传输。

这最初是Google QUIC的一部分(也是人们说QUIC对数据包丢失有好处的
原因之一),但它没有包含在标准化的QUIC版本1中,因为它的性能影响
尚未得到证实。不过,研究人员现在正在用它进行积极的实验,你可以通
过使用PQUIC-FEC Download Experiments (↦
https://play.google.com/store/apps/details?id=org.pquic.pquic_fec_android)应用程序来帮助
他们。

多路径 QUIC (↦ https://tools.ietf.org/html/draft-liu-multipath-quic)

我们之前讨论过连接迁移,以及它在从 Wi-Fi 迁移到蜂窝时如何提供帮


助。但是,这是否也意味着我们可以同时使用Wi-Fi和蜂窝网络?同时使用
两个网络将为我们带来更多的可用带宽和更高的鲁棒性!这是多路径背后
的主要概念。

这又是谷歌尝试过的东西,但由于其固有的复杂性而没有进入QUIC版本
1。然而,研究人员已经展示了 (↦ https://multipath-quic.org/)它的高潜力,它可
能会进入QUIC版本2。请注意,TCP多路径 (↦ https://www.multipath-tcp.org/)也
存在,但这花了将近十年的时间才变得实际可用。

QUIC (↦ https://tools.ietf.org/html/draft-ietf-quic-datagram)和HTTP / 3 (↦
https://datatracker.ietf.org/doc/html/draft-ietf-masque-h3-datagram)

上的不可靠数据 正如我们所看到的,QUIC是一个完全可靠的协议。但
是,由于它运行在不可靠的UDP上,因此我们可以向QUIC添加一个功能以
发送不可靠的数据。这在建议的数据报扩展中进行了概述。当然,您不希
望使用它来发送网页资源,但对于游戏和实时视频流之类的事情来说,它
可能很方便。这样,用户将获得UDP的所有好处,但具有QUIC级加密和
(可选)拥塞控制。

WebTransport (↦ https://web.dev/webtransport/)

Browser不会直接向JavaScript公开TCP或UDP,这主要是出于安全问题。相
反,我们必须依赖HTTP级API,如Fetch和更灵活的WebSocket (↦
https://hpbn.co/websocket/)和WebRTC (↦ https://hpbn.co/webrtc/)协议。这一系列选项
中的最新选项称为WebTransport,它主要允许您以更低级的方式使用HTTP
/ 3(以及扩展为QUIC)(尽管如果需要,它也可以回退到TCP和HTTP /
2)。

至关重要的是,它将包括通过HTTP / 3使用不可靠数据的能力(请参阅上
3 (
一点),这应该使游戏之类的东西更容易在浏览器中实现。对于普通的
(JSON)API调用,当然,您仍将使用Fetch,这也将在可能的情况下自动
使用HTTP / 3。WebTransport目前仍在进行大量讨论,因此尚不清楚它最
终会是什么样子。在浏览器中,只有Chromium目前正在开发公共概念验
证实现 (↦ https://groups.google.com/a/chromium.org/g/web-transport-dev/c/6PwPFy9fVfw)。

DASH和HLS视频流

对于非直播视频(想想YouTube和Netflix),浏览器通常使用基于HTTP的
动态自适应流(DASH)或HTTP实时流(HLS)协议。两者基本上都意味
着您将视频编码为较小的块(2到10秒)和不同的质量级别(720p,
1080p,4K等)。

在运行时,浏览器估计您的网络可以处理的最高质量(或给定用例的最佳
质量),并通过HTTP从服务器请求相关文件。由于浏览器无法直接访问
TCP堆栈(因为它通常在内核中实现),因此它偶尔会在这些估计中犯一
些错误,或者需要一段时间才能对不断变化的网络条件做出反应(导致视
频停滞)。

由于QUIC是作为浏览器的一部分实现的,因此通过让流估计器访问低级协
议信息 (↦ https://dl.acm.org/doi/abs/10.1145/3386367.3431901)(例如丢失率,带宽估计
等),可以对此进行相当多的改进。其他研究人员也一直在尝试将可靠和
不可靠的数据混合用于视频流 (↦ https://www.researchgate.net/profile/Mirko-
Palmer/publication/327930175_The_QUIC_Fix_for_Optimal_Video_Streaming/links/5f60ea97299
bf1d43c063075/The-QUIC-Fix-for-Optimal-Video-Streaming.pdf),并取得了一些有希望的
结果。

HTTP/3

以外的协议 由于 QUIC 是一种通用传输协议,我们可以预期现在通过 TCP


运行的许多应用层协议也将在 QUIC 之上运行。一些正在进行的工作包括
DNS-over-QUIC (↦ https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic),SMB-
over-QUIC (↦ https://techcommunity.microsoft.com/t5/itops-talk-blog/smb-over-quic-files-
without-the-vpn/ba-p/1183449),甚至SSH-over-QUIC (↦
https://datatracker.ietf.org/doc/html/draft-bider-ssh-quic-09)。由于这些协议通常具有与
HTTP和网页加载非常不同的要求,因此我们讨论的QUIC的性能改进可能
更适合这些协议。
这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN-6)

QUIC 版本 1 只是一个开始。Google之前尝试过的许多高级性能导向功能都没有
进入第一次迭代。但是,目标是快速发展协议,以高频率引入新的扩展和功
能。因此,随着时间的推移,QUIC(和HTTP / 3)应该变得明显比TCP(和
HTTP / 2)更快,更灵活。

结论# (↦ #Conclusion)
在本系列的第二部分中,我们讨论了 HTTP/3(尤其是 QUIC)的许多不同性能
特性和方面。我们已经看到,虽然这些功能中的大多数看起来都非常有影响
力,但在实践中,在我们一直在考虑的网页加载用例中,它们可能不会为普通
用户做那么多事情。

例如,我们已经看到QUIC使用UDP并不意味着它可以突然使用比TCP更多的带
宽,也不意味着它可以更快地下载您的资源。广受赞誉的 0-RTT 功能实际上是

一种微优化,可以节省一次往返行程,其中您可以发送大约 5 KB(在最坏的情
如果存在突发数据包丢失或加载渲染阻止资源,则 HoL 阻塞删除效果不佳。连
况下)。
接迁移是高度情境化的,HTTP/3 没有任何主要的新功能可以使其比 HTTP/2 更
快。

因此,您可能希望我建议您跳过HTTP / 3和QUIC。何必呢,对吧?但是,我绝
对不会做这样的事情!尽管这些新协议可能不会对快速(城市)网络上的用户
有太大帮助,但新功能确实有可能对高度移动的用户和慢速网络上的人产生很
大的影响。

即使在西方市场,比如我自己的比利时,我们通常拥有快速设备和高速蜂窝网
络,这些情况也会影响1%到甚至10%的用户群,具体取决于您的产品。一个例子
是火车上有人拼命地试图在你的网站上查找一条关键信息,但不得不等待45秒
才能加载。我当然知道我一直处于这种情况,希望有人部署QUIC来让我摆脱困
境。

但是,在其他国家和地区,情况要糟糕得多。在那里,普通用户可能看起来更
像是比利时最慢的10%,而最慢的1%可能根本看不到加载的页面。在世界许多地
方 (↦ https://infrequently.org/2021/03/the-performance-inequality-gap/),Web 性能是一个可访
方 ( https://infrequently.org/2021/03/the performance inequality gap/),Web 性能是 个可访
问性和包容性问题 (↦ https://hookedoncode.com/2020/07/performance-is-accessibility/)。

这就是为什么我们永远不应该只在自己的硬件上测试我们的页面(但也使用像
Pagetest (↦ https://www.webpagetest.org/)这样的服务),以及为什么你一定要部署
QUIC和HTTP / 3。特别是如果您的用户经常在移动中或不太可能访问快速蜂窝
网络,即使您在有线MacBook Pro上没有太多注意到,这些新协议也可能会产生
天壤之别。有关更多详细信息,我强烈建议Fastly就此问题发布文章 (↦
https://www.fastly.com/blog/how-http3-and-quic-help-long-tail-connections)。

如果这不能完全说服你,那么请考虑QUIC和HTTP / 3将继续发展并在未来几年
中变得更快。获得一些早期协议经验将得到回报,让您尽快获得新功能的好
处。此外,QUIC在后台实施安全和隐私最佳实践,使世界各地的所有用户受
益。

终于被说服了吗?然后继续阅读本系列的第 3 部分 (↦
https://www.smashingmagazine.com/2021/09/http3-practical-deployment-options-part3/),了解如何
在实践中使用新协议。

第 1 部分:HTTP/3 历史和核心概念 (↦

https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/)

本文针对的是刚接触 HTTP/3 和一般协议的人,主要讨论基础知


识。

第2部分:HTTP / 3性能特性

这一部分更深入,技术性更强。已经了解基础知识的人可以从这里
开始。

第 3 部分:实用的 HTTP/3 部署选项 (↦


https://www.smashingmagazine.com/2021/09/http3-practical-deployment-options-
part3/)

本系列的第三篇文章介绍了自己部署和测试 HTTP/3 所涉及的挑


战。它详细说明了如何以及是否应该更改网页和资源。


(vf, il, al)

探索更多

You might also like