查看原文
其他

【第3199期】HTTP/3:性能改进

桃猿 前端早读课 2024-03-09

前言

本文探讨了 HTTP/3 和 QUIC 对网页加载性能的改进,重点关注慢网络上用户的受益。文章解释了延迟和带宽对网页加载速度的影响,以及 TCP 和 QUIC 在拥塞控制方面的区别。最后,提到了许多人对 QUIC 速度优势的误解,指出其实际工作原理和对性能的影响。今日前端早读课文章由 @桃猿翻译分享,公号:桃猿授权。

@桃猿:目前在 shopeepay 担任前端工程师,专注于支付领域的业务。

正文从这开始~~

【第3197期】HTTP/3 简介:核心概念中,我们探讨了为什么我们需要 HTTP/3 和底层的 QUIC 协议,以及它们的主要新特性。

在这第二部分,我们将重点关注 QUIC 和 HTTP/3 为网页加载带来的性能改进。然而,我们也对实践中这些新特性可能产生的影响保持一些怀疑。

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

本部分比第一部分技术性更强点点,尽管它将大部分深层次的内容交给外部来源,仅侧重于解释这些事物对普通 Web 开发者的重要性。

关于速度的入门

讨论性能和 “速度” 可能很快变得复杂,因为许多基础因素影响网页加载的 “慢”。由于我们在处理网络协议,我们主要将重点放在两个最重要的网络方面:延迟和带宽。

延迟:从 A 点(例如,客户端)发送数据包到 B 点(服务器)的时间。它受到光速或实际上是信号在电线或空气中传播的速度的物理限制。这意味着延迟通常取决于 A 和 B 之间的物理世界距离。

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

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

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

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

了解这些概念的完美理解并不是这篇文章后面部分所必需的,但有一个共同的高层次定义会很有帮助。有关更多信息,我建议您查看 Ilya Grigorik 在他的《高性能浏览器网络》一书中关于延迟和带宽的精彩章节 https://hpbn.co/primer-on-latency-and-bandwidth/。

拥塞控制

性能的一个方面涉及传输协议如何高效地利用网络的全部(物理)带宽(即大致上每秒可以发送或接收多少数据包)。这直接影响页面资源下载的速度。有人声称 QUIC 在这方面比 TCP 更优秀,但这并不正确。

你知道吗?

例如,TCP 连接并不会立即以全带宽发送数据,因为这可能会导致网络过载(拥塞)。这是因为,正如我们所说,每个网络链路每秒只能处理一定数量的数据。超过这个限制,就只能丢弃多余的数据包,导致数据包丢失。

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

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

此外,即使我们知道可用的物理带宽,也并不意味着我们可以全部使用。通常情况下,网络上同时有几个用户活动,每个用户都需要公平分享可用带宽的一部分。

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

在连接开始时,它仅发送少量数据包(实践上在 10 到 100 个数据包之间,或大约 14 到 140 KB 的数据),并等待一个往返时间,直到接收方发送这些数据包的确认。如果它们全部得到确认,这意味着网络可以处理该发送速率,然后我们可以尝试以更多的数据重复这个过程(实践上,每次迭代时发送速率通常会翻倍)。

这样,发送速率将持续增长,直到某些数据包未被确认(表示数据包丢失和网络拥塞)。这个阶段通常被称为 “慢启动”。在检测到数据包丢失后,TCP 会降低发送速率,然后(一段时间后)再次开始以(更小的)增量增加发送速率。这种减少然后增长的逻辑对每次数据包丢失都会重复。最终,这意味着 TCP 将不断尝试达到其理想的、公平的带宽份额。该机制在图 1 中有所说明。

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

这是对拥塞控制的极度简化解释。实际上,还有许多其他因素起作用,如缓冲区过大、由于拥塞导致 RTT 波动以及多个并发发送方需要的公平共享带宽。因此,存在许多不同的拥塞控制算法,而且今天仍在不断发明,没有一种在所有情况下都表现最佳。

虽然 TCP 的拥塞控制使其更加稳健,但这也意味着它需要一段时间才能达到最佳的发送速率,这取决于 RTT 和实际可用的带宽。对于网页加载,这种慢启动方法也会影响诸如首次内容绘制等指标,因为在前几次往返中只能传输少量数据(几十 KB 到几百 KB)。你可能听说过将关键数据保持在小于 14KB 的建议。

选择更积极的方法可能会在高带宽和高延迟网络上取得更好的结果,尤其在你不在乎偶尔的数据包丢失时。这就是我再次看到有关 QUIC 工作方式的许多误解的地方。

正如第一部分讨论的,QUIC 在理论上更少受到数据包丢失(及相关的队头阻塞)的影响,因为它独立地处理每个资源的字节流的数据包丢失。此外,QUIC 运行在用户数据报协议(UDP)上,与 TCP 不同,UDP 没有内置的拥塞控制功能;它允许你以任何速率尝试发送,并且不会重传丢失的数据。

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

实际上,事实与此相距甚远:QUIC 实际上使用与 TCP 非常相似的带宽管理技术。它也从较低的发送速率开始,并随着时间的推移增加,使用确认作为衡量网络容量的关键机制。这是因为 QUIC 需要可靠性,以便用于诸如 HTTP 之类的应用,因为它需要对其他 QUIC(和 TCP!)连接公平,并且因为其去除首部阻塞并不能很好地应对数据包丢失(正如我们将在下面看到的)。

然而,这并不意味着 QUIC 不能在带宽管理方面比 TCP 更加智能一些。这主要是因为 QUIC 比 TCP 更灵活,更容易演化。正如我们所说,拥塞控制算法今天仍在不断发展,我们可能需要调整一些东西以充分发挥 5G 的潜力。

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

相反,大多数 QUIC 实现目前是在 “用户空间” 进行的(我们通常在其中运行本机应用程序),并且是开源的,明确是为了鼓励更广泛的开发人员进行实验(正如已经展示的那样,例如 Facebook 的版本)。

QUIC 延迟确认频率扩展提案是一个明显的例子。默认情况下,QUIC 对于每收到的 2 个数据包会发送一个确认,而这个扩展允许端点选择性地每 10 个数据包发送一次确认。研究表明,这在卫星和高带宽网络上可以带来显著的速度提升,因为传输确认数据包的开销降低了。在 TCP 中添加这样的扩展需要很长时间被采用,而对于 QUIC 来说,部署要容易得多。

因此,我们可以期待 QUIC 的灵活性将促使更多的实验和更好的拥塞控制算法,这反过来也可能被倒回到 TCP 中以改进它。

你知道吗?

官方的 QUIC 恢复 RFC 9002 规定了使用 NewReno 拥塞控制算法。虽然这种方法是稳健的,但他有些过时,且实践中使用并不广泛。那么,为什么在 QUIC RFC 中使用它呢?第一个原因是,当 QUIC 启动时,NewReno 是最新的拥塞控制算法,它本身也是标准化的。更先进的算法,如 BBR 和 CUBIC,要么还没有标准化,要么只是最近「While this approach is robust, it’s also somewhat outdated and not used extensively in practice anymore.」才成为 RFC。

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

需要重申的是,拥塞控制算法不是特定于 TCP 或 QUIC 的;它们可以被任一协议使用,希望 QUIC 的进展最终也能在 TCP 堆栈中找到应用。

你知道吗?

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

这一切意味着什么?

QUIC 仍受制于物理法则和对互联网上其他发送方的友好性需求。这意味着它不会像 TCP 一样神奇地更快地下载您网站的资源。然而,QUIC 的灵活性意味着更容易进行新的拥塞控制算法实验,这应该在将来改善 TCP 和 QUIC 的性能。

0-RTT 连接建立

第二个性能方面涉及在建立新连接之前需要多少往返次数才能发送有用的 HTTP 数据(例如,页面资源)。有人声称 QUIC 比 TCP + TLS 快两到三个往返,但实际上只有一个。

你知道吗?

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

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

图 2:TCP + TLS 与 QUIC 连接建立的比较。

你可能会想知道为什么 TCP + TLS 握手不能简单地合并,在同一个往返中完成。尽管这在概念上是可能的(QUIC 确实做到了),但最初的设计并不是这样的,因为我们需要能够在 TCP 上使用和不使用 TLS。换句话说,TCP 根本不支持在握手期间发送非 TCP 的东西。曾经有过尝试通过 TCP Fast Open 扩展来添加此功能;然而,如第一部分所讨论的,这在大规模部署上变得困难。

幸运的是,QUIC 从一开始就考虑到了 TLS,并因此将传输和加密握手结合在一个单一的机制中。这意味着 QUIC 握手只需要一个往返就能完成,这比 TCP + TLS 1.3 少了一个往返(参见图 2c)。

你可能感到困惑,因为你可能已经读到过 QUIC 比 TCP 快两到三个往返,而不仅仅是一个。这是因为大多数文章只考虑最坏的情况(TCP + TLS 1.2,(a)),没有提到现代 TCP + TLS 1.3 也 “只需” 两个往返((b)很少显示)。虽然一个往返的速度提升很好,但几乎察觉不到,尤其是在快速网络上(例如,往返时间少于 50 毫秒时),尽管在慢速网络和连接到远程服务器时会更加受益。

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

【第2943期】测试中如何处理 Http 请求?

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

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

再次强调,会话恢复和 0-RTT 是我经常看到被错误解释为是 QUIC 特有功能的事物。实际上,这些实际上是 TLS 1.2 中以某种形式存在的 TLS 功能,现在在 TLS 1.3 中已经完全成熟。

在下图 3 中可以看到,QUIC 的性能优势主要来自于 TCP(以及 HTTP/2 和甚至 HTTP/1.1)。即使使用 0-RTT,QUIC 仍然只比 TCP + TLS 1.3 堆栈仅快一个往返。所声称的三个往返比较的是图 2 的 (a) 和图 3 的 (f),正如我们所见,这并不真的公平。

图 3:TCP + TLS 与 QUIC 0-RTT 连接建立的比较。

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

其次,而且在这里至关重要的是,它允许服务器在发送数据之前确保打开连接的客户端确实是他们声称的人和地点。如果您还记得我们在第一部分中如何定义与 4 元组的连接,您就会知道客户端主要通过其 IP 地址来标识。这是一个问题的关键之处:IP 地址可以被欺骗!

假设攻击者通过 QUIC 0-RTT 请求获取一个非常大的文件。然而,他们欺骗他们的 IP 地址,使其看起来像 0-RTT 请求来自受害者的计算机。这在下图 4 中显示。QUIC 服务器无法检测 IP 是否被欺骗,因为这是它从该客户端看到的第一个数据包(或几个数据包)。

图 4:攻击者可以欺骗其 IP 地址发送 0-RTT 请求到 QUIC 服务器,触发对受害者的放大攻击。

如果服务器简单地开始向欺骗的 IP 发回大文件,它可能会过载受害者的网络带宽(特别是如果攻击者并行执行许多这些伪造的请求)。请注意,受害者将丢弃 QUIC 响应,因为它不期望收到传入的数据,但这并不重要:他们的网络仍然需要处理这些数据包!

【第2876期】XSS 攻击22年:全面调查及系统综述

这被称为反射或放大攻击,是黑客执行分布式拒绝服务(DDoS)攻击的一种重要方式。请注意,在使用 TCP + TLS 的 0-RTT 时,这种情况不会发生,因为 TCP 握手必须在 0-RTT 请求甚至与 TLS 握手一起完成之前完成。

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

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

此外,其他安全问题可能导致例如 “重放攻击”,限制你可以执行的 HTTP 请求类型。例如,Cloudflare 只允许在 0-RTT 中不带查询参数的 HTTP GET 请求。这更加限制了 0-RTT 的实用性。

幸运的是,QUIC 有一些选项可以改善这个问题。例如,服务器可以检查 0-RTT 是否来自其以前曾建立有效连接的 IP。然而,这仅在客户端保持在相同网络上时有效(这在某种程度上限制了 QUIC 的连接迁移功能)。即使它奏效,QUIC 的响应仍受拥塞控制器慢启动逻辑的限制,我们在上面讨论过;因此,除了节省的一个往返之外,没有额外的大规模速度提升。

你知道吗?

有趣的是,QUIC 的三倍放大限制在图 2c 中的正常非 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 设置相比,它最多可以节省一个往返时间。实际上在第一次往返中可以发送的数据量还受到一些安全考虑的限制。

因此,这个特性主要在以下两种情况下表现出色:一是用户处于延迟非常高的网络上(比如,往返时间超过 200 毫秒的卫星网络),二是你通常不发送大量数据的情况。后者的例子包括缓存密集型的网站,以及定期通过 API 和其他协议(如 DNS-over-QUIC)获取小型更新的单页应用程序。谷歌在 QUIC 上看到良好的 0-RTT 结果的原因之一是它在已经经过大幅优化的搜索页面上进行了测试,查询响应非常小。

在其他情况下,你最多只能获得几十毫秒的性能提升,如果你已经使用 CDN(如果你关心性能的话,你应该使用 CDN)的话,甚至可能更少!

【第2784期】从cdnjs 的漏洞来看前端的供应链攻击与防御

连接迁移

第三个性能特性使得在网络之间传输时 QUIC 保持现有连接更快,通过保持现有连接而不断开连接来实现。尽管这确实有效,但这种类型的网络切换并不经常发生,并且连接仍然需要重置其发送速率。

正如在第一部分中讨论的,QUIC 的连接 ID(CIDs)允许在切换网络时执行连接迁移。我们通过一个客户端在进行大文件下载时从 Wi-Fi 网络切换到 4G 的示例进行了说明。在 TCP 上,该下载可能需要中止,而在 QUIC 上可能会继续。

然而,首先要考虑这种类型的情景实际上有多经常发生。你可能认为在建筑物内在 Wi-Fi 接入点之间移动或在路上在移动时在蜂窝塔之间切换也会发生这种情况。然而,在这些设置中(如果设置正确),你的设备通常会保持其 IP 不变,因为在更低的协议层上进行无线基站之间的过渡。因此,它仅在你在完全不同的网络之间切换时才会发生,我认为这并不经常发生。

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

然而,加载页面通常需要几秒钟的时间,因此与网络切换同时发生的可能性也不会很常见。另外,对于这是一个紧迫问题的用例,通常已经采取了其他缓解措施。例如,支持大文件下载的服务器可以支持 HTTP 分片请求以允许可恢复的下载。

因为网络 1 关闭和网络 2 变得可用之间通常有一些重叠时间,视频应用程序可以打开多个连接(每个网络 1 个),在旧网络完全消失之前进行同步。用户仍然会注意到切换,但不会完全中断视频流。

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

由于这种初始发送速率通常太低,以至于无法真正支持诸如视频流之类的事物,即使在 QUIC 上也会看到一些质量损失或故障。在某种程度上,连接迁移更多地是为了防止连接上下文的波动和服务器开销,而不是为了提高性能。

你知道吗?

请注意,正如我们在 0-RTT 中讨论的那样,我们可以设计一些先进的技术来改善连接迁移。例如,我们可以尝试记住可用的带宽在上一次在特定网络上的,并在新的迁移中尝试更快地升级到该水平。此外,我们还可以设想不仅仅在网络之间切换,而是同时使用两者。这个概念被称为多路径,我们在下面会更详细地讨论。

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

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

我们在第一部分讨论了,为了安全起见,QUIC 不仅使用单个 CID。相反,它在执行主动迁移时更改 CIDs。实际上,情况要复杂得多,因为客户端和服务器都有单独的 CIDs 列表(被称为源 CID 和目标 CID,在 QUIC RFC 中)。这在下图中有所说明。

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

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

因此,QUIC 在负载平衡器后面部署的后端服务器的 CIDs 需要具有可预测的格式,以便负载平衡器可以根据 CID 推导出正确的后端服务器,即使在迁移后也是如此。关于如何做到这一点,IETF 的提案文档中有一些选项。为了使所有这些成为可能,服务器需要能够选择自己的 CID,如果连接发起方(对于 QUIC,始终是客户端)选择了 CID 是不可能的。这就是为什么在 QUIC 中有客户端 CIDs 和服务器 CIDs 之间存在分离的原因。

这都意味着什么呢?

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

然而,根据您的使用情况或用户配置文件,它可能会产生很大的影响。如果您的网站或应用程序通常在移动中使用(比如 Uber 或 Google Maps 之类的东西),那么您可能会受益更多,相比于如果您的用户通常坐在桌子后面。同样,如果您专注于持续交互(无论是视频聊天,协作编辑还是游戏),那么最糟糕的场景下会比您访问一个新闻网站改进更多。

去除 Head-Of-Line Blocking (队头阻塞)

第四个性能特性旨在通过减轻头阻塞问题,使 QUIC 在具有高丢包率的网络上更快。虽然理论上是这样,但实际上对网页加载性能的影响可能只会带来轻微的好处。

然而,要理解这一点,我们首先需要绕个弯,谈论流优先级和多路复用。

流优先级

正如第一部分讨论的那样,TCP 的单个数据包丢失可能会延迟多个在途资源的数据,因为 TCP 的字节流抽象将所有数据视为单个文件的一部分。另一方面,QUIC 深知存在多个并发的字节流,并且可以按流处理丢失的数据。然而,正如我们之前所见,这些流实际上并非真正并行传输数据:相反,流数据是多路复用到单个连接上的。这种多路复用可以以许多不同的方式进行。

例如,对于流 A、B 和 C,我们可能看到 ABCABCABCABCABCABCABCABC 的数据包序列,其中我们在每个数据包中更改活动流(我们称之为轮流)。然而,我们还可能看到 AAAAAAAABBBBBBBBCCCCCCCC 的相反模式,其中每个流在开始下一个流之前完成(我们称之为顺序)。当然,在这些极端之间还有许多其他选项(AAAABBCAAAAABBC…,AABBCCAABBCC…,ABABABCCCC… 等)。这种多路复用方案是动态的,并由一个称为流优先级的 HTTP 级别功能驱动(本文稍后讨论)。

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

不同浏览器中的流多路复用差异。

幸运的是,我们可以相对容易地解释基本原理。正如您可能知道的那样,一些资源可能会阻止渲染。这对 CSS 文件和 HTML 头元素中的一些 JavaScript 来说是这样。在加载这些文件时,浏览器无法绘制页面(或者执行新的 JavaScript,例如)。

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

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

如果我们使用轮流复用器(图 6 中的顶行),我们实际上会延迟每个资源的总完成时间,因为它们都需要与其他资源共享带宽。由于只能在它们完全加载后使用它们,这会产生显著的延迟。但是,如果我们按顺序复用它们(图 6 中的底行),我们会看到 A 和 B 会更早完成(并且可以被浏览器使用),而不会实际延迟 C 的完成时间。

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

然而,对于大多数网页资源来说,顺序多路复用效果最好。这就是例如 Google Chrome 在上面的视频中所做的,而 Internet Explorer 则使用最坏情况的轮流复用器。

数据包丢失韧性

现在我们知道并非所有流总是同时活跃的,它们可以以不同的方式进行复用。我们可以考虑一下如果发生数据包丢失会发生什么,正如第一部分所述,如果一个 QUIC 流经历数据包丢失,那么其他活跃的流仍然可以使用(而在 TCP 中,所有流都将暂停)。

然而,正如我们刚刚所看到的,同时拥有许多并发活跃的流通常对 Web 性能不利,因为即使没有数据包丢失,它可能会延迟一些关键的(渲染阻塞)资源!我们宁愿只有一个或两个流同时活跃,使用顺序复用器。然而,这减少了 QUIC 的 Head-of-Line(HoL)阻塞去除的影响。

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

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

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

我们看到了一种矛盾:顺序复用(AAAABBBBCCCC)通常对 Web 性能更好,但它不能充分利用 QUIC 的 HoL 阻塞去除。循环复用(ABCABCABCABC)对 HoL 阻塞更好,但对 Web 性能更差。因此,一个最佳实践或优化可能会导致另一个最佳实践或优化的失效。

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

正如上面讨论的,导致数据包丢失的一个重要原因是网络被过多的数据过载,必须放弃多余的数据包。这就是为什么拥塞控制器开始缓慢发送的原因。然而,它随后会增加发送速率,直到... 发生数据包丢失!

换句话说,旨在防止网络过载的机制实际上会(以受控的方式)过载网络。在大多数网络上,这发生在很长时间之后,当发送速率增加到每个往返的包数以百计时。当它们达到网络的极限时,通常会一次性丢失其中的几个,导致突发性的丢包模式。

你知道吗?

这是我们希望使用单个(TCP)连接与 HTTP/2 而不是 HTTP/1.1 的 6 到 30 个连接的原因之一。因为每个单独的连接以几乎相同的方式增加其发送速率,HTTP/1.1 在开始时可能会得到很好的加速,但随着它们导致网络过载,连接实际上可能会导致大量数据包丢失。

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

你知道吗?

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

因此,假设我们正在使用每个数据包的循环复用器(ABCABCABCABCABCABCABCABC...)以充分利用 HoL 阻塞去除,然后我们遇到了 4 个数据包的突发丢失。我们看到这将始终影响所有 3 个流(见图 8,中间行)!在这种情况下,QUIC 的 HoL 阻塞去除没有任何好处,因为所有流都必须等待它们自己的重传。

图 8:根据使用的复用器和数据包丢失模式,受影响的流可能更多或更少

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

最终,预测 QUIC 的 HoL 阻塞去除的实际影响是困难的,因为它取决于流的数量,丢失突发的大小和频率,流数据实际上是如何使用的等等。然而,目前大多数研究结果表明,对于 Web 页面加载的用例,它不会有太大帮助,因为我们通常希望较少的并发流。

如果您想更详细了解这个主题或只是一些具体的例子,请查看我的关于 HTTP HoL 阻塞的深入文章:https://calendar.perfplanet.com/2020/head-of-line-blocking-in-quic-and-http-3-the-details/。

你知道吗?

与前面的部分一样,一些先进的技术可以在这方面帮助我们。例如,现代拥塞控制器使用数据包调度。这意味着它们不会在单个突发中发送 100 个数据包,而是在整个往返时间内分散它们。这在概念上降低了过载网络的机会,而 QUIC Recovery RFC 强烈建议使用它。此外,一些拥塞控制算法,如 BBR,不会在导致数据包丢失之前持续增加其发送速率,而是在此之前减速(通过观察 RTT 的波动,因为当网络变得过载时,RTTs 也会上升)。

虽然这些方法降低了数据包丢失的整体机会,但不一定降低其突发性。

这都意味着什么呢?

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

仍然有一些情况可能会看到更多的改进。这些情况主要是在第一个完整页面加载的典型用例之外 —— 例如,当资源不是渲染阻塞时,当它们可以逐步处理时,当流完全独立时,或者在同一时间发送的数据较少时。

例如,对于良好缓存的页面的重复访问以及单页面应用程序中的后台下载和 API 调用等情况可能会看到一些好处。例如,Facebook 在使用 HTTP/3 在其原生应用程序中加载数据时看到了一些 HoL 阻塞移除的好处。

提升 UDP 和 TLS 性能

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

首先,我们已经讨论过,QUIC 对 UDP 的使用更多是出于灵活性和可部署性的考虑,而不是性能。事实证明,直到最近,通过 UDP 发送 QUIC 数据包通常比发送 TCP 数据包慢得多。这部分是因为这些协议通常的实现位置和方式(见下图 9)。


图 9:TCP 和 QUIC 之间的实现差异。

如上所述,TCP 和 UDP 通常直接在操作系统的快速内核中实现。相反,TLS 和 QUIC 的实现主要在较慢的用户空间中(请注意,这在 QUIC 中实际上并不是必需的,主要是因为它更加灵活)。这使得 QUIC 比 TCP 慢一些。

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

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

其次,QUIC 有很多开销,因为它对每个数据包进行单独加密。这比在 TCP 上使用 TLS 要慢,因为在那里你可以分块加密数据包(最多约 16 KB 或 11 个数据包),这更有效。这是 QUIC 中做出的有意的权衡,因为大规模加密可能导致其自己形式的 Head-of-Line(HoL)阻塞。

与第一个观点不同,我们无法通过添加额外的 API 使 UDP(或者 QUIC)更快。在这里,QUIC 将始终相对于 TCP + TLS 存在固有的劣势。然而,在实践中,通过优化加密库和允许 QUIC 数据包头部进行批量加密的巧妙方法,这是相当可控的。

因此,虽然 Google 最早的 QUIC 版本比 TCP + TLS 慢一倍,但近年来情况肯定有所改善。例如,在最近的测试中,微软经过大量优化的 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 实现将会(部分地)移动到操作系统内核中(就像 TCP 一样)或绕过它(有些实现已经这样做,比如 MsQuic 和 Quant)。我们还可以期待 QUIC 专用硬件的推出。

但是,TCP + TLS 可能仍然是某些用例的首选选项。例如,Netflix 已表示它可能不会很快转移到 QUIC,因为它已大量投资于定制的 FreeBSD 设置,以通过 TCP + TLS 传输其视频。

同样,Facebook 表示 QUIC 可能主要用于终端用户和 CDN 边缘之间,而不是数据中心之间或边缘节点与源服务器之间,因为其开销较大。总的来说,在接下来的几年中,非常高带宽的场景可能仍然更喜欢 TCP + TLS。

你知道吗?

优化网络堆栈是一个深度且技术性的领域,上面仅仅触及到了表面(并且忽略了很多细微差别)。如果你足够勇敢,或者想了解诸如 GRO/GSO、SO_TXTIME、内核绕过以及 sendmmsg() 和 recvmmsg() 等术语的含义,我可以推荐一些由 Cloudflare 和 Fastly 撰写的优化 QUIC 的优秀文章,以及 Microsoft 的详尽代码走读,以及 Cisco 的深入讲解。最后,一位 Google 工程师关于随着时间推移,优化他们的 QUIC 实现:https://www.youtube.com/watch?v=xxN4FfwaANk 的精彩主题演讲。

这都意味着什么呢?

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

HTTP/3 特性

迄今为止,我们主要谈论了 QUIC 与 TCP 的性能特性。但是,HTTP/3 与 HTTP/2 有什么区别呢?正如在第一部分中讨论的那样,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 中,这些控制消息可能以任何顺序到达(并应用),甚至可能使特性产生与预期相反的效果!这里不需要详细讨论技术细节,但本文的前半部分「first half of this paper」应该让你对这种复杂性有所了解。

因此,HTTP/3 的特性的内部机制和实现方式必须发生变化。一个具体的例子是 HTTP 头部压缩,它降低了重复大型 HTTP 头部(例如,cookie 和用户代理字符串)的开销。在 HTTP/2 中,使用 HPACK 设置进行压缩,而在 HTTP/3 中,这已经被重新设计为更复杂的 QPACK。这两个系统提供相同的功能(即头部压缩),但实现方式却大不相同。关于这个主题的一些深度技术讨论和图表可以在 Litespeed 博客:https://blog.litespeedtech.com/tag/quic-header-compression-design-team/ 上找到。

类似的情况也适用于驱动流复用逻辑的优先级特性,我们在上面简要讨论过。在 HTTP/2 中,这是使用复杂的 “依赖树” 设置实现的,该设置明确尝试模拟所有页面资源及其相互关系(更多信息请参见 “HTTP 资源优先级的终极指南:https://www.youtube.com/watch?v=nH4iRpFnf1c” 演讲)。在 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 和蜂窝网络吗?同时使用两个网络将为我们提供更多可用带宽和增强的稳健性!这是多路径的主要概念。

这同样是 Google 进行实验的一个方向,但由于其固有的复杂性,它未能进入 QUIC 版本 1。然而,研究人员后来展示了其高潜力,它可能会在 QUIC 版本 2 中实现。请注意,TCP 多路径也存在,但几乎花了十年时间才变得实用。

QUIC 和 HTTP/3 上的不可靠数据正如我们所见,QUIC 是一个完全可靠的协议。然而,由于它运行在不可靠的 UDP 上,我们可以为 QUIC 添加一个功能,即发送不可靠的数据。这在提议的数据包扩展中概述。当然,你不希望用它来发送网页资源,但对于诸如游戏和实时视频流等事物,这可能很方便。这样,用户将获得 UDP 的所有优势,但具有 QUIC 级别的加密和(可选的)拥塞控制。

WebTransport 浏览器不直接向 JavaScript 公开 TCP 或 UDP,主要是出于安全考虑。相反,我们必须依赖于 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),浏览器通常使用动态自适应流媒体传输(DASH)或 HTTP Live Streaming(HLS)协议。两者基本上意味着将视频编码为较小的块(2 到 10 秒)和不同的质量级别(720p、1080p、4K 等)。

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

由于 QUIC 是作为浏览器的一部分实现的,这可以通过使流媒体估算器访问低级协议信息(如丢包率、带宽估算等)而得到相当大的改进。其他研究人员也一直在尝试为视频流传输混合可靠和不可靠的数据,取得了一些令人鼓舞的结果。

除了 HTTP/3 的其他协议由于 QUIC 是一种通用的传输协议,我们可以期望许多现在运行在 TCP 上的应用层协议也在 QUIC 上运行。一些正在进行中的工作包括 DNS-over-QUIC、SMB-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(Head-of-Line)阻塞的消除在存在突发的数据包丢失或加载渲染阻塞资源时效果不佳。连接迁移是高度情境化的,并且 HTTP/3 没有任何可以使其比 HTTP/2 更快的重大新功能。

因此,您可能会期望我建议您跳过 HTTP/3 和 QUIC。为什么要麻烦呢?然而,我绝对不会这样做!尽管这些新协议在快速(城市)网络上可能对用户没有太多帮助,但这些新特性确实有可能对高度移动的用户和慢速网络上的用户产生重大影响。

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

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

这就是为什么我们永远不应仅在我们自己的硬件上测试页面(还要使用诸如 Webpagetest 之类的服务),并且为什么您绝对应该部署 QUIC 和 HTTP/3 的原因。特别是如果您的用户经常在移动中或不太可能接入快速蜂窝网络,这些新协议可能会产生翻天覆地的变化,即使您在插着电缆的 MacBook Pro 上可能察觉不到太多。有关更多详细信息,强烈推荐阅读 Fastly 关于此问题的文章:https://www.fastly.com/blog/how-http3-and-quic-help-long-tail-connections。

如果这还不能完全说服您,那么请考虑 QUIC 和 HTTP/3 将在未来继续发展并变得更快。提前体验这些协议将在将来产生回报,使您能够尽快享受到新功能的好处。此外,QUIC 在后台强制执行安全性和隐私最佳实践,这有益于全球所有用户。

关于本文
译者:@桃猿
译文:https://mp.weixin.qq.com/s/_Up3hAl1byxMVlbQNZjNWQ
作者:@Robin Marx
原文:https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。

继续滑动看下一个

【第3199期】HTTP/3:性能改进

向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存