1.1.2.1[一步步跑完前端学习路线] 前端内容系统化梳理-Internet-应用层-HTTPS/3协议-性能功能

120 阅读53分钟

引言

本文是一篇外文翻译,原文是由Robin Marx所写,他是一位深入研究HTTP/3和QUIC的Web 性能的网络协议研究员。

他将分三个以下部分深入探讨HTTP/3的内容:

本文即为第二部分内容的翻译,旨在知识传播。

开始

欢迎回到这个关于新 HTTP/3 协议的系列。在第 1 部分中,我们了解了我们究竟为什么需要 HTTP/3 和底层 QUIC 协议,以及它们的主要新功能是什么。

在第二部分中,我们将重点介绍 QUIC 和 HTTP/3 为网页加载带来的性能改进。但是,我们也会对这些新功能在实践中的预期影响持怀疑态度。

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

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

速度入门 #

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

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

实际上,这意味着典型的延迟在概念上很小,大约在 10 到 200 毫秒之间。但是,这只是一种方法:对数据包的响应也需要返回。双向延迟通常称为往返时间 (RTT)。

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

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

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

虽然本文的其余部分不需要对这些概念有完美的理解,但有一个通用的高级定义会很好。有关更多信息,我建议您查看 Ilya Grigorik 在他的《High Performance Browser Networking》一书中关于延迟和带宽的精彩章节

拥塞控制 #

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

您是否了解?

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

正如第 1 部分所讨论的,对于像 TCP 这样的可靠协议,从数据包丢失中恢复的唯一方法是重新传输数据的新副本,这需要一次往返。尤其是在高延迟网络上(例如,RTT 超过 50 毫秒),数据包丢失会严重影响性能。

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

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

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

在连接开始时,它只发送几个数据包(实际上,范围在 10 到 100 个数据包之间,或大约 14 到 140 KB 的数据)并等待一次往返,直到接收方发回这些数据包的确认。如果它们都被确认,这意味着网络可以处理该发送速率,我们可以尝试重复该过程,但使用更多数据(在实践中,发送速率通常会在每次迭代时翻倍)。

这样,发送速率会继续增长,直到某些数据包未得到确认(这表明数据包丢失和网络拥塞)。第一阶段通常称为“缓慢启动”。检测到数据包丢失后,TCP 会降低发送速率,并且(一段时间后)再次开始增加发送速率,尽管增量(小得多)。此后,对于每个数据包丢失,都会重复此 reduce-then-grow 逻辑。最终,这意味着 TCP 将不断尝试达到其理想的、公平的带宽份额。这种机制如图 1 所示。

TCP congestion control

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

这是对拥塞控制的极其过于简化的解释。在实践中,还有许多其他因素在起作用,例如缓冲区膨胀拥塞导致的 RTT 波动,以及多个并发发送方需要获得其公平份额的带宽这一事实。因此,存在许多不同的拥塞控制算法,并且今天仍在发明大量算法,但没有一种算法在所有情况下都能发挥最佳性能。

虽然 TCP 的拥塞控制使其功能强大,但这也意味着需要一段时间才能达到最佳发送速率,具体取决于 RTT 和实际可用带宽。对于网页加载,这种缓慢启动的方法也会影响量度,例如第一次内容绘制,因为在最初的几次往返中只能传输少量数据(数十到几百 KB)。(您可能听说过将关键数据保持在 14 KB 以下的建议。

因此,选择更激进的方法可能会在高带宽和高延迟网络上产生更好的结果,尤其是在您不关心偶尔的数据包丢失的情况下。这就是我再次看到许多关于 QUIC 工作原理的误解的地方。

第 1 部分所述,理论上,QUIC 受数据包丢失(以及相关的队头 (HOL) 阻塞)的影响较小,因为它独立处理每个资源字节流上的数据包丢失。此外,QUIC 通过用户数据报协议 (UDP) 运行,与 TCP 不同,UDP 没有内置拥塞控制功能;它允许您尝试以您想要的任何速率发送,并且不会重新传输丢失的数据。

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

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

但是,这并不意味着 QUIC 在管理带宽方面不能比 TCP 更聪明。这主要是因为 QUIC 比 TCP 更灵活、更容易发展。正如我们所说,拥塞控制算法今天仍在大力发展,我们可能需要进行调整,以充分利用 5G

但是,TCP 通常在操作系统 (OS) 的内核中实现,这是一个安全且受限制更严格的环境,对于大多数操作系统来说,它甚至不是开源的。因此,优化拥塞逻辑通常只由少数开发人员完成,而且发展缓慢。

相比之下,大多数 QUIC 实现目前都是在 “用户空间” (我们通常运行原生应用程序的地方) 完成的,并且是开源的,明确地鼓励更广泛的开发人员进行实验(例如,Facebook 已经表明了这一点)。

另一个具体的例子是 QUIC 的*延迟确认频率*扩展提案。默认情况下,QUIC 每接收 2 个数据包发送一次确认,但此扩展允许终端节点确认,例如,每 10 个数据包一次。事实证明,这在卫星和非常高带宽的网络上具有很大的速度优势,因为传输确认数据包的开销降低了。为 TCP 添加这样的扩展需要很长时间才能被采用,而对于 QUIC 来说,它更容易部署。

因此,我们可以预期,随着时间的推移,QUIC 的灵活性将导致更多的实验和更好的拥塞控制算法,这反过来也可以向后移植到 TCP 以改进它。

您是否了解?

官方 QUIC Recovery RFC 9002 指定了 NewReno 拥塞控制算法的使用。虽然这种方法很可靠,但它也有些过时,在实践中不再广泛使用。那么,为什么它会出现在 QUIC RFC 中呢?第一个原因是,当 QUIC 启动时,NewReno 是最新的拥塞控制算法,它本身就是标准化的。更高级的算法,如 BBR 和 CUBIC,要么仍未标准化,要么最近才成为 RFC。

第二个原因是 NewReno 是一个相对简单的设置。因为算法需要一些调整来处理 QUIC 与 TCP 的差异,所以用更简单的算法更容易解释这些变化。因此,RFC 9002 应该更多地理解为“如何使拥塞控制算法适应 QUIC”,而不是“这是你应该用于 QUIC 的东西”。事实上,大多数生产级 QUIC 实现都对 Cubic 和 BBR 进行了自定义实现。

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

您是否了解?

请注意,拥塞控制旁边是一个称为流量控制的相关概念。这两个功能在 TCP 中经常被混淆,因为它们都说使用 “TCP 窗口” ,尽管实际上有两个窗口:拥塞窗口和 TCP 接收窗口。但是,对于我们感兴趣的网页加载用例,流控制的作用要小得多,因此我们在这里跳过它。更深入的信息可用。

这一切意味着什么?#

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

0-RTT 连接设置 #

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

您是否了解?

正如我们在第 1 部分中所说,在交换 HTTP 请求和响应之前,连接通常会执行一次 (TCP) 或两次 (TCP + TLS) 握手。这些握手交换 Client 端和服务器都需要知道的初始参数,例如,为了加密数据。

如下面的图 2 所示 ,每次握手至少需要一次往返才能完成 (TCP + TLS 1.3, (b)),有时需要两次 (TLS 1.2 和之前的 (a))。这是低效的,因为在发送第一个 HTTP 请求之前,我们至少需要两次往返握手等待时间(开销),这意味着至少需要等待三次往返才能收到第一个 HTTP 响应数据(返回的红色箭头)。在慢速网络上,这可能意味着 100 到 200 毫秒的开销。

TCP congestion control

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

您可能想知道为什么 TCP + TLS 握手不能简单地组合起来,在同一次往返中完成。虽然这在概念上是可能的(QUIC 正是这样做的),但最初并不是这样设计的,因为我们需要能够在有和没有 TLS 的情况下使用 TCP。换句话说,TCP 根本不支持在握手期间发送非 TCP 内容。已经有人努力通过 TCP Fast Open 扩展添加它;但是,正如第 1 部分所述,事实证明,这很难大规模部署

幸运的是,QUIC 在设计之初就考虑到了 TLS,因此确实将传输和加密握手结合在一个机制中。这意味着 QUIC 握手总共只需要一次往返即可完成,这比 TCP + TLS 1.3 少了一次往返(见上面的图 2c)。

您可能会感到困惑,因为您可能已经读到过 QUIC 比 TCP 快 2 次甚至 3 次往返,而不仅仅是 1 次。这是因为大多数文章只考虑了最坏的情况(TCP + TLS 1.2,(a)),而没有提到现代 TCP + TLS 1.3 也“只”需要两次往返((b) 很少出现)。虽然一次往返的速度提升很好,但并不令人惊讶。尤其是在快速网络(例如,小于 50 毫秒的 RTT)上,这几乎不会引起注意,尽管慢速网络和连接到远程服务器会带来更多收益。

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

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

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

会话恢复和 0-RTT 都是我经常看到的被错误解释为 QUIC 特定功能的东西。实际上,这些实际上是 TLS 功能,它们已经以某种形式存在于 TLS 1.2 中,现在在 TLS 1.3 中已经完全成熟。

换句话说,正如您在下面的图 3 中看到的那样,我们也可以获得这些特性相对于 TCP(因此也包括 HTTP/2 甚至 HTTP/1.1)的性能优势!我们看到,即使使用 0-RTT,QUIC 仍然只比运行最佳的 TCP + TLS 1.3 堆栈快一次往返。QUIC 快了三个往返的说法来自于将图 2 的 (a) 与图 3 的 (f) 进行比较,正如我们所看到的,这并不真正公平。

TCP + TLS versus QUIC 0-RTT connection set-up.

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

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

其次,也是这里最关键的一点是,它允许服务器在发送数据之前确保打开连接的客户端实际上是他们所说的人和位置。如果您还记得我们在第 1 部分中是如何定义具有 4 元组的连接,您就会知道客户端主要由其 IP 地址标识。这就是问题所在:IP 地址可以被欺骗

假设攻击者通过 HTTP over QUIC 0-RTT 请求一个非常大的文件。但是,他们伪造了自己的 IP 地址,使 0-RTT 请求看起来像是来自受害者的计算机。这如下面的图 4 所示。QUIC 服务器无法检测 IP 是否是伪造的,因为这是它从该客户端看到的第一个数据包。

0-RTT amplification attack on the victim.

图 4:攻击者在向 QUIC 服务器发送 0-RTT 请求时可以伪造他们的 IP 地址,从而触发对受害者的放大攻击。(大预览

如果服务器随后简单地开始将大文件发送回欺骗性 IP,则最终可能会使受害者的网络带宽过载(尤其是在攻击者同时执行许多此类虚假请求时)。请注意,受害者会丢弃 QUIC 响应,因为它不需要传入数据,但这并不重要:他们的网络仍然需要处理数据包!

这称为*反射或放大攻击*,是黑客执行分布式拒绝服务 (DDoS) 攻击的重要方式。请注意,当使用 TCP + TLS 上的 0-RTT 时,不会发生这种情况,正是因为 TCP 握手需要先完成,然后才能将 0-RTT 请求与 TLS 握手一起发送。

因此,QUIC 在响应 0-RTT 请求时必须保守,限制它发送的响应数据量,直到验证客户端是真实客户端而不是受害者。对于 QUIC,此数据量已设置为从客户端接收量的三倍

换句话说,QUIC 的最大“放大系数”为 3,这被确定为性能有用性和安全风险之间的可接受权衡(尤其是与一些放大系数超过 51,000 倍的事件相比)。因为客户端通常首先只发送一到两个数据包,所以 QUIC 服务器的 0-RTT 回复上限仅为 4 到 6 KB(包括其他 QUIC 和 TLS 开销),这有点不那么令人印象深刻。

此外,其他安全问题还可能导致 “重放攻击” 等,这限制了您可以执行的 HTTP 请求类型。例如,Cloudflare 只允许在 0-RTT 中没有查询参数的 HTTP GET 请求。这些进一步限制了 0-RTT 的有用性。

幸运的是,QUIC 可以选择让它变得更好一点。例如,服务器可以检查 0-RTT 是否来自之前有过有效连接的 IP。但是,这仅在客户端保持在同一网络上时才有效(在一定程度上限制了 QUIC 的连接迁移功能)。即使它有效,QUIC 的响应仍然受到我们上面讨论的拥塞控制器的慢启动逻辑的限制;因此,除了节省一次往返之外,没有额外的大量速度提升

您是否了解?

有趣的是,图 2c 中 QUIC 的三倍放大限制也计入其正常的非 0-RTT 握手过程。例如,如果服务器的 TLS 证书太大,无法容纳在 4 到 6 KB 内,则可能会出现问题。在这种情况下,它必须被拆分,第二个块必须等待第二次往返发送(在确认前几个数据包进入后,表明客户端的 IP 没有被欺骗)。在这种情况下,QUIC 的握手可能最终仍需要两次往返,等于 TCP + TLS!这就是为什么对于 QUIC 来说,证书压缩等技术将格外重要。

您是否了解?

可能是某些高级设置能够缓解这些问题,足以使 0-RTT 更有用。例如,服务器可以记住上次看到客户端时有多少可用带宽,从而减少拥塞控制在重新连接(非欺骗性)客户端时启动缓慢的限制。学术界已经对此进行了研究,甚至在 QUIC 中提议扩展来做到这一点。一些公司也已经在做这种事情来加速 TCP。

另一种选择是让客户端发送一个或两个以上的数据包(例如,再发送 7 个带填充的数据包),因此,即使在连接迁移之后,三倍限制也会转换为更有趣的 12 到 14 KB 响应。我在我的一篇论文中写过这个问题。

最后,如果 QUIC 服务器认为这样做在某种程度上是安全的,或者如果他们不关心潜在的安全问题(毕竟,没有协议警察阻止这种情况),他们也可以故意增加三倍限制。

这一切意味着什么?#

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

因此,如果您的用户位于延迟非常高的网络(例如,RTT 超过 200 毫秒的卫星网络)上,或者您通常不发送太多数据,则此功能将大放异彩。后者的一些示例包括大量缓存的网站,以及通过 API 和其他协议(如 DNS-over-QUIC)定期获取小更新的单页应用程序。Google 看到 QUIC 的 0-RTT 结果非常好的原因之一是,它在已经高度优化的搜索页面上对其进行了测试,其中的查询响应非常小。

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

连接迁移 #

第三个性能功能通过保持现有连接不变,使 QUIC 在网络之间传输时更快。虽然这确实有效,但这种类型的网络更改并不经常发生,连接仍然需要重置其发送速率。

第 1 部分所述,QUIC 的连接 ID (CID) 允许它在切换网络时执行连接迁移。我们以一个客户端在进行大文件下载时从 Wi-Fi 网络迁移到 4G 来说明这一点。在 TCP 上,可能必须中止该下载,而对于 QUIC,它可能会继续。

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

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

但是,加载页面通常需要几秒钟的时间,因此与网络切换重合的情况也不会很常见。此外,对于这是一个紧迫问题的使用案例,其他缓解措施通常已经到位。例如,提供大文件下载的服务器可以支持 HTTP 范围请求以允许断点续传下载。

由于网络 1 断开和网络 2 可用之间通常存在一些重叠时间,因此视频应用可以打开多个连接(每个网络 1 个),在旧网络完全消失之前同步它们。用户仍会注意到该开关,但不会完全删除视频源。

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

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

您是否了解?

请注意,正如上面 0-RTT 所讨论的,我们可以设计一些高级技术来改进连接迁移。例如,我们可以再次尝试记住上次给定网络上有多少可用带宽,并尝试更快地升级到该级别以进行新的迁移。此外,我们不仅可以设想简单地在网络之间切换,而且可以同时使用两者。这个概念称为 multipath我们将在下面更详细地讨论它

到目前为止,我们主要讨论了主动连接迁移,即用户在不同网络之间移动。但是,也存在被动连接迁移的情况,其中某个网络本身会更改参数。一个很好的例子是网络地址转换 (NAT) 重新绑定。虽然对 NAT 的全面讨论不在本文的讨论范围之内,但它主要意味着连接的端口号可以在任何给定时间更改,而不会发出警告。在大多数路由器中,UDP 的这种情况也比 TCP 更频繁地发生。

如果发生这种情况,QUIC CID 将不会更改,并且大多数实现将假定用户仍在同一物理网络上,因此不会重置拥塞窗口或其他参数。QUIC 还包括一些功能,例如 PIN 和超时指示器,以防止这种情况发生,因为这通常发生在长时间空闲的连接中。

我们在第 1 部分中讨论了 QUIC 不仅仅出于安全原因使用单个 CID。相反,它会在执行主动迁移时更改 CID。在实践中,它甚至更加复杂,因为客户端和服务器都有单独的 CID 列表(在 QUIC RFC 中称为源 CID 和目标 CID)。这在下面的图 5 中进行了说明。

QUIC uses separate source and destination CIDs

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

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

因此,部署在负载均衡器后面的 QUIC 后端服务器必须具有可预测的 CID 格式,以便负载均衡器可以从 CID 派生正确的后端服务器,即使在迁移后也是如此。IETF 的拟议文档中介绍了一些执行此操作的选项。为了实现这一切,服务器需要能够选择自己的 CID,如果连接发起方(对于 QUIC 来说,它始终是客户端)选择了 CID,这是不可能的。这就是 QUIC 中客户端和服务器 CID 之间存在分裂的原因。

这一切意味着什么?#

因此,连接迁移是一个情境特征。例如,Google 的初步测试显示,其用例的改进百分比较低。许多 QUIC 实现尚未实现此功能。即使是那些这样做的公司,通常也会将其限制在移动客户端和应用程序上,而不是它们的桌面等价物。有些人甚至认为该功能不是必需的,因为在大多数情况下,使用 0-RTT 打开新连接应该具有类似的性能属性。

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

消除 Head-Of-Line 阻塞 #

第四个性能功能旨在通过缓解队头 (HoL) 阻塞问题,使 QUIC 在具有大量数据包丢失的网络上更快。虽然这在理论上是正确的,但我们将看到,在实践中,这可能只会为网页加载性能提供很小的好处。

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

流优先级 #

第 1 部分所述,单个 TCP 数据包丢失可能会延迟多个传输中资源的数据,因为 TCP 的字节流抽象将所有数据视为单个文件的一部分。另一方面,QUIC 非常清楚存在多个并发字节流,并且可以在每个流的基础上处理丢失。然而,正如我们所看到的,这些流并不是真正并行传输数据:相反,流数据被多路复用到单个连接上。这种多路复用可以以多种不同的方式发生。

例如,对于流 A、B 和 C,我们可能会看到 ABCABCABCABCABCABCABCAB 的数据包序列,其中我们更改了每个数据包中的活动流(我们称之为循环)。但是,我们也可能看到与 AAAAAAAABBBBBBBBCCCCCCCCCC 相反的模式,其中每个流在开始下一个流之前都已完整完成(我们称之为 sequential)。当然,在这些极端之间还有许多其他选择(AAAABBCAAAAABBC...AABBCCAABBCC...ABABABCCCC...等)。多路复用方案是动态的,由称为流优先级的 HTTP 级功能驱动(本文稍后将讨论)。

事实证明,您选择的多路复用方案会对网站加载性能产生巨大影响。您可以在下面的视频中看到这一点,由 Cloudflare 提供,因为每个浏览器都使用不同的多路复用器。原因相当复杂,我已经写了几篇关于这个主题的学术论文,并在一次会议上谈到了它Webpagetest 的 Patrick Meenan 甚至有一个关于这个主题的三个小时的教程

Stream prioritization in different browsers

流多路复用差异可能会对不同浏览器中的网站加载产生很大影响。(大预览

幸运的是,我们可以相对容易地解释基础知识。你可能知道,某些资源可能会受到渲染阻塞。CSS 文件和 HTML head 元素中的某些 JavaScript 就是这种情况。在加载这些文件时,浏览器无法绘制页面(或者,例如,执行新的 JavaScript)。

更重要的是,CSS 和 JavaScript 文件需要完整下载才能使用(尽管它们通常可以逐步解析和编译)。因此,需要尽快加载这些资源,并具有最高优先级。让我们考虑一下,如果 A、B 和 C 都是阻止渲染的资源,会发生什么情况。

Render blocking multiplexing impact

图 6:流多路复用方法会影响(渲染阻塞)资源完成时间。(大预览

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

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

尽管如此,对于大多数网页资源,事实证明,顺序多路复用的性能最好。例如,这就是上面视频中 Google Chrome 所做的,而 Internet Explorer 使用的是最坏情况的循环多路复用器。

数据包丢失弹性 #

现在我们知道所有流并不总是同时处于活动状态,并且它们可以以不同的方式进行多路复用,我们可以考虑如果出现数据包丢失会发生什么。如第 1 部分所述,如果一个 QUIC 流发生数据包丢失,则仍然可以使用其他活动流(而在 TCP 中,所有都将暂停)。

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

例如,想象一下,发送方在给定时间可以传输 12 个数据包(见下面的图 7)——请记住,这受到拥塞控制器的限制)。如果我们用流 A 的数据填充所有 12 个数据包(因为它是高优先级和渲染阻塞 — 想想 main.js),那么我们在那个 12 个数据包的窗口中将只有一个活动流。

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

HoL blocking with round-robin versus sequential multiplexing

图 7:数据包丢失的影响取决于所使用的多路复用器。(请注意,我们假设每个流要发送的数据比前面的类似图像中多。(大预览

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

而且情况变得更糟。到目前为止,我们一直假设单个数据包一次丢失一个。但是,这并不总是正确的,因为 Internet 上的数据包丢失通常是“突发的”,这意味着多个数据包通常会同时丢失

如上所述,数据包丢失的一个重要原因是网络过载,数据过多,不得不丢弃多余的数据包。这就是拥塞控制器开始缓慢发送的原因。但是,它会继续提高其发送速率,直到...存在数据包丢失!

换句话说,旨在防止网络过载的机制实际上会使网络过载(尽管以受控的方式)。在大多数网络上,这发生在相当长的一段时间后,此时发送速率已增加到每次往返数百个数据包。当这些值达到网络极限时,其中几个通常会一起丢弃,从而导致突发丢失模式。

您是否了解?

这就是我们想改用 HTTP/2 的单个 (TCP) 连接,而不是 HTTP/1.1 的 6 到 30 个连接的原因之一。因为每个单独的连接都以几乎相同的方式提高其发送速率,所以 HTTP/1.1 在开始时可能会获得很好的加速,但实际上,这些连接可能会开始导致彼此之间的大量数据包丢失,因为它们会导致网络过载。

当时,Chromium 开发人员推测,这种行为导致了互联网上看到的大部分数据包丢失。这也是 BBR 成为一种常用拥塞控制算法的原因之一,因为它使用观察到的 RTT 中的波动,而不是数据包丢失来评估可用带宽。

您是否了解?

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

因此,假设我们正在使用每数据包循环多路复用器 (ABCABCABCABCABCABCABCABC...) 来充分利用 HoL 阻塞消除,而我们只得到了 4 个数据包的突发损失。我们看到,这总是会影响所有 3 个流(参见图 8,中间行)!在这种情况下,QUIC 的 HoL 阻塞移除没有任何好处,因为所有流都必须等待自己的重传

Packet loss patterns and their interaction with different multiplexers

图 8:根据使用的多路复用器和丢包模式,或多或少的流受到影响。(大预览

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

最后,预测 QUIC 的 HoL 阻塞消除的实际影响是困难的,因为它取决于流的数量、丢失突发的大小和频率、流数据的实际使用方式等。但是,此时的大多数结果表明,它对网页加载的用例没有太大帮助,因为在那里我们通常需要更少的并发流。

如果您想了解有关此主题的更多详细信息或一些具体示例,请查看我关于 HTTP HoL 阻止的深入文章

您是否了解?

与前面的部分一样,一些高级技术可以在这里帮助我们。例如,现代拥塞控制器使用数据包步调。这意味着它们不会在一次突发中发送 100 个数据包,而是将它们分散在整个 RTT 中。从概念上讲,这降低了网络过载的可能性,QUIC Recovery RFC 强烈建议使用它。作为补充,一些拥塞控制算法(如 BBR)在导致数据包丢失之前不会一直提高其发送速率,而是在此之前退缩(例如,通过查看 RTT 波动,因为当网络过载时 RTT 也会上升)。

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

这一切意味着什么?#

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

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

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

UDP 和 TLS 性能 #

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

首先,我们已经讨论过 QUIC 对 UDP 的使用更多的是关于灵活性和可部署性,而不是性能。直到最近,通过 UDP 发送 QUIC 数据包通常比发送 TCP 数据包慢得多的事实进一步证明了这一点。这部分是由于这些协议通常的实施地点和方式(见下面的图 9)。

Implementation differences between TCP and QUIC

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

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

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

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

其次,QUIC 开销很大,因为它单独加密每个数据包。这比使用 TLS over TCP 慢,因为您可以以块的形式加密数据包(一次最多约 16 KB 或 11 个数据包),效率更高。这是在 QUIC 中有意识地做出的权衡,因为批量加密会导致其自身形式的 HoL 阻塞

与第一点不同,我们可以添加额外的 API 来使 UDP(以及 QUIC)更快,在这里,QUIC 始终具有 TCP + TLS 的固有缺点。但是,这在实践中也是相当可控的,例如,通过优化的加密库和允许批量加密 QUIC 数据包标头的巧妙方法。

因此,虽然 Google 最早的 QUIC 版本仍然比 TCP + TLS 慢两倍,但此后情况确实有所改善。例如,在最近的测试中,Microsoft 高度优化的 QUIC 堆栈能够获得 7.85 Gbps,而在同一系统上,TCP + TLS 的速度为 11.85 Gbps(因此,QUIC 的速度约为 TCP + TLS 的 66%)。

这是与最近的 Windows 更新一起实现的,它使 UDP 更快(为了全面比较,该系统上的 UDP 吞吐量为 19.5 Gbps)。Google 的 QUIC 堆栈的最优化版本目前比 TCP + TLS 慢约 20%。Fastly 在不太先进的系统上进行的早期测试甚至声称具有相同的性能(约 450 Mbps),这表明根据用例,QUIC 绝对可以与 TCP 竞争。

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

其次,未来仍有很多机会来优化 QUIC 实现。例如,随着时间的推移,一些 QUIC 实现将(部分)移动到 OS 内核(很像 TCP)或绕过它(有些已经这样做了,如 MsQuic)。我们还可以期待 QUIC 特定的硬件可用。

尽管如此,在某些用例中,TCP + TLS 可能仍然是首选选项。例如,Netflix 表示它可能不会很快转向 QUIC,它已经投入了大量资金用于自定义 FreeBSD 设置,以通过 TCP + TLS 流式传输其视频。

同样,Facebook 表示,由于 QUIC 的开销较大,它可能主要在最终用户和 CDN 的边缘之间使用,而不是在数据中心之间或边缘节点和源服务器之间使用。一般来说,非常高带宽的场景可能会继续支持 TCP + TLS,尤其是在未来几年。

您是否了解?

优化网络堆栈是一个很深的技术性兔子洞,上面的内容只是触及了表面(错过了很多细微差别)。如果你足够勇敢,或者你想知道 GRO/GSOSO_TXTIME、内核旁路以及 sendmmsg() 和 recvmmsg() 等术语的含义,我可以推荐一些关于 Cloudflare 和 Fastly 优化 QUIC 优秀文章,以及 Microsoft 的广泛代码演练,以及 Cisco 的深入演讲。最后,一位 Google 工程师发表了一个非常有趣的主题演讲,介绍了如何随着时间的推移优化他们的 QUIC 实现

这一切意味着什么?#

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

HTTP/3 功能 #

到目前为止,我们主要讨论了 QUIC 与 TCP 中的新性能特性。但是,HTTP/3 与 HTTP/2 相比呢?正如第 1 部分所讨论的,HTTP/3 实际上是 HTTP/2-over-QUIC,因此,新版本中没有引入真正的重大新功能。这与从 HTTP/1.1 到 HTTP/2 的迁移不同,后者的规模要大得多,并引入了标头压缩、流优先级和服务器推送等新功能。这些功能都仍在 HTTP/3 中,但在后台实现方式存在一些重要差异。

这主要是因为 QUIC 删除 HoL 阻止的工作原理。正如我们所讨论的,流 B 上的丢失不再意味着流 A 和 C 将必须等待 B 的重新传输,就像它们在 TCP 上所做的那样。因此,如果 A、B 和 C 都按该顺序发送了一个 QUIC 数据包,则它们的数据很可能以 A、C、B 的形式传送到浏览器(并由浏览器处理)!换句话说,与 TCP 不同,QUIC 不再在不同的流中完全排序

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

因此,HTTP/3 必须更改功能的内部机制和实现。一个具体的例子是 HTTP 标头压缩,它降低了重复的大型 HTTP 标头(例如 Cookie 和用户代理字符串)的开销。在 HTTP/2 中,这是使用 HPACK 设置完成的,而对于 HTTP/3,这已被重新设计为更复杂的 QPACK。这两个系统提供相同的功能(即标头压缩),但方式完全不同。可以在 Litespeed 博客上找到有关此主题的一些出色的深入技术讨论和图表。

驱动 stream multiplexing logic 的 prioritization feature 也是如此,我们在上面已经简要讨论了。在 HTTP/2 中,这是使用复杂的“依赖树”设置实现的,该设置明确尝试对所有页面资源及其相互关系进行建模(更多信息在“HTTP 资源优先级终极指南”讨论中)。直接在 QUIC 上使用此系统将导致一些可能非常错误的树布局,因为将每个资源添加到树中将是一个单独的控制消息。

此外,这种方法被证明是不必要的复杂,导致许多服务器上的许多实施错误和效率低下以及性能不佳。这两个问题都导致 HTTP/3 的优先级系统以一种更简单的方式重新设计。这种更直接的设置使得某些高级方案难以或无法实施(例如,在单个连接上代理来自多个客户端的流量),但仍支持多种网页加载优化选项。

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

最后,还有服务器推送。此功能允许服务器发送 HTTP 响应,而无需先等待对它们的明确请求。从理论上讲,这可以提供出色的性能提升。然而,在实践中,事实证明它很难正确使用并且实现不一致。因此,它甚至可能从 Google Chrome 中删除

尽管如此,它仍然定义为 HTTP/3 中的一个功能(尽管很少有实现支持它)。虽然它的内部工作原理没有前两个功能那么大的变化,但它也已经适应了 QUIC 的非确定性排序。但遗憾的是,这对解决它的一些长期问题几乎没有帮助。

这一切意味着什么?#

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

需要关注的未来发展 #

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

  • 前向纠错
    这项技术的目的同样是提高 QUIC 对数据包丢失的弹性。它通过发送数据的冗余副本来实现这一点(尽管经过巧妙的编码和压缩,因此它们不会那么大)。然后,如果数据包丢失但冗余数据到达,则不再需要重新传输。

    这最初是 Google QUIC 的一部分(也是人们说 QUIC 对丢包有好处的原因之一),但它没有包含在标准化的 QUIC 版本 1 中,因为它的性能影响尚未得到证实。不过,研究人员现在正在使用它进行积极的实验,您可以使用 PQUIC-FEC 下载实验应用程序来帮助他们。

  • 多路径 QUIC
    我们之前已经讨论过连接迁移,以及它在从 Wi-Fi 迁移到蜂窝网络时如何提供帮助。但是,这是否也意味着我们可以同时使用 Wi-Fi 和蜂窝网络?同时使用两个网络将为我们提供更多可用带宽和更高的健壮性!这就是 multipath 背后的主要概念。

    这又是 Google 尝试过的东西,但由于其固有的复杂性而没有进入 QUIC 版本 1。然而,研究人员此后显示出它的巨大潜力,它可能会进入 QUIC 第 2 版。请注意,TCP 多路径也存在,但花了将近十年的时间才真正可用。

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

  • 网络传输
    浏览器不会直接将 TCP 或 UDP 暴露给 JavaScript,主要是出于安全考虑。相反,我们必须依赖 HTTP 级别的 API,例如 Fetch 和更灵活的 WebSocket 和 WebRTC 协议。这一系列选项中最新的选项称为 WebTransport,它主要允许您以更底层的方式使用 HTTP/3(以及扩展的 QUIC)(尽管如果需要,它也可以回退到 TCP 和 HTTP/2)。

    至关重要的是,它将包括通过 HTTP/3 使用不可靠数据的能力(参见上一点),这应该会使游戏等功能在浏览器中实现相当容易。对于普通的 (JSON) API 调用,您当然仍将使用 Fetch,它也会在可能的情况下自动使用 HTTP/3。WebTransport 目前仍在激烈讨论中,因此尚不清楚它最终会是什么样子。在所有浏览器中,只有 Chromium 目前正在进行公开的概念验证实现

  • DASH 和 HLS 视频流
    对于非实时视频(想想 YouTube 和 Netflix),浏览器通常使用 Dynamic Adaptive Streaming over HTTP (DASH) 或 HTTP Live Streaming (HLS) 协议。两者基本上都意味着您将视频编码为更小的块(2 到 10 秒)和不同的质量级别(720p、1080p、4K 等)。

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

    因为 QUIC 是作为浏览器的一部分实现的,所以通过让 streaming estimator 访问低级协议信息(例如丢失率、带宽估计等),这可以得到相当大的改进。其他研究人员也一直在尝试混合可靠和不可靠的数据以进行视频流,并取得了一些可喜的结果。

  • HTTP/3 以外的协议
    由于 QUIC 是一种通用传输协议,我们可以预期现在在 TCP 上运行的许多应用层协议也将在 QUIC 上运行。一些正在进行的工作包括 DNS-over-QUICSMB-over-QUIC甚至 SSH-over-QUIC。由于这些协议通常具有与 HTTP 和网页加载截然不同的要求,因此我们讨论的 QUIC 性能改进可能更适合这些协议。

这一切意味着什么?#

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

  结论 #

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

例如,我们已经看到 QUIC 对 UDP 的使用并不意味着它可以突然使用比 TCP 更多的带宽,也不意味着它可以更快地下载您的资源。经常受到赞誉的 0-RTT 功能实际上是一种微优化,可以为您节省一次往返,其中您可以发送大约 5 KB(在最坏的情况下)。

如果存在突发数据包丢失或加载渲染阻塞资源时,HoL 阻止删除效果不佳。连接迁移是高度情境化的,HTTP/3 没有任何可以使其比 HTTP/2 更快的主要新功能。

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

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

然而,还有其他国家和地区的情况要糟糕得多。在那里,普通用户可能看起来更像比利时最慢的 10%,而最慢的 1% 可能根本看不到加载的页面。在世界许多地方,Web 性能是一个可访问性和包容性问题

这就是为什么我们永远不应该只在我们自己的硬件上测试我们的页面(但也应该使用像 Webpagetest 这样的服务),也是为什么你绝对应该部署 QUIC 和 HTTP/3。特别是如果您的用户经常在移动中或不太可能访问快速蜂窝网络,即使您在有线 MacBook Pro 上没有注意到太多,这些新协议也可能会产生天壤之别。有关更多详细信息,我强烈推荐 Fastly 关于此问题的帖子

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

终于被说服了?然后继续阅读本系列的第 3 部分,了解如何在实践中使用新协议。