HTTP/3:实用的部署选项(第 3 部分)
已发表: 2022-03-10您好,欢迎收看新 HTTP/3 和 QUIC 协议这个由三部分组成的系列的最后一部分! 如果在前两部分之后——HTTP/3 历史和核心概念以及 HTTP/3 性能特性——你确信开始使用新协议是一个好主意(你应该这样做!),那么这最后一部分包括所有你需要知道才能开始!
首先,我们将讨论您需要对页面和资源进行哪些更改以最佳地使用新协议(这是简单的部分)。 接下来,我们将了解如何设置服务器和客户端(这是最难的部分,除非您使用的是内容交付网络 (CDN))。 最后,我们将看看您可以使用哪些工具来评估新协议的性能影响(这几乎是不可能的部分,至少目前是这样)。
- 第 1 部分:HTTP/3 历史和核心概念
本文主要针对 HTTP/3 和一般协议的新手,主要讨论基础知识。 - 第 2 部分:HTTP/3 性能特性
这一个更深入和技术。 已经了解基础知识的人可以从这里开始。 - 第 3 部分:实用的 HTTP/3 部署选项
本系列的第三篇文章解释了自己部署和测试 HTTP/3 所涉及的挑战。 它详细说明了如何以及是否应该更改您的网页和资源。
页面和资源的更改
让我们从一些好消息开始:如果您已经使用 HTTP/2,那么在迁移到 HTTP/3 时,您可能不需要对页面或资源进行任何更改! . 这是因为,正如我们在第 1 部分和第 2 部分中所解释的,HTTP/3 实际上更像是 HTTP/2-over-QUIC,并且两个版本的高级特性保持不变。 因此,对 HTTP/2 所做的任何更改或优化仍然适用于 HTTP/3,反之亦然。
但是,如果您仍在使用 HTTP/1.1,或者您忘记了向 HTTP/2 的过渡,或者您从未真正针对 HTTP/2 进行过调整,那么您可能想知道这些更改是什么以及为什么需要它们。 但是,即使在今天,您也很难找到一篇详细介绍细微差别的最佳实践的好文章。 这是因为,正如我在第 1 部分的介绍中所说,早期 HTTP/2 的大部分内容都过于乐观地认为它在实践中的效果如何,坦率地说,其中一些内容存在重大错误和糟糕的建议。 可悲的是,许多这种错误信息今天仍然存在。 这是我写这个关于 HTTP/3 的系列的主要动机之一,以帮助防止这种情况再次发生。
我目前可以推荐的关于 HTTP/2 的最佳多合一细微差别源是 Barry Pollard 所著的《 HTTP/2 in Action》一书。 然而,由于这是一个付费资源,我不想让你在这里猜测,我在下面列出了一些要点,以及它们与 HTTP/3 的关系:
1.单连接
HTTP/1.1 和 HTTP/2 之间最大的区别是从 6 到 30 个并行 TCP 连接切换到单个底层 TCP 连接。 我们在第 2 部分中讨论了一点,单个连接如何仍然可以像多个连接一样快,因为拥塞控制如何导致更多或更早的数据包丢失更多的连接(这抵消了它们聚合更快启动的好处)。 HTTP/3 延续了这种方法,但“只是”从一个 TCP 切换到一个 QUIC 连接。 这种差异本身并没有太大的作用(它主要减少了服务器端的开销),但它导致了以下大部分内容。
2. 服务器分片和连接合并
切换到单连接设置在实践中非常困难,因为许多页面被分片到不同的主机名甚至服务器(如img1.example.com
和img2.example.com
)。 这是因为浏览器最多只能为每个单独的主机名打开六个连接,所以有多个允许更多连接! 如果不更改此 HTTP/1.1 设置,HTTP/2 仍会打开多个连接,从而降低其他功能(例如优先级(见下文))的实际工作效果。
因此,最初的建议是撤消服务器分片并尽可能在单个服务器上整合资源。 HTTP/2 甚至提供了一项功能,使从 HTTP/1.1 设置的过渡更容易,称为连接合并。 粗略地说,如果两个主机名解析为相同的服务器 IP(使用 DNS)并使用类似的 TLS 证书,那么浏览器甚至可以跨两个主机名重用单个连接。
在实践中,连接合并可能很难正确处理,例如,由于涉及 CORS 的几个微妙的安全问题。 即使您正确设置了它,您仍然可以轻松地以两个单独的连接结束。 问题是,这并不总是坏事。 首先,由于优先级和多路复用实现不佳(见下文),单个连接很容易比使用两个或更多连接慢。 其次,由于拥塞控制器的竞争,使用过多的连接可能会导致早期数据包丢失。 然而,只使用几个(但仍然不止一个)可以很好地平衡拥塞增长和更好的性能,尤其是在高速网络上。 由于这些原因,我相信一点点分片仍然是一个好主意(例如,两到四个连接),即使使用 HTTP/2。 事实上,我认为大多数现代 HTTP/2 设置的性能都和它们一样好,因为它们的关键路径中仍然有一些额外的连接或第三方负载。
3. 资源捆绑和内联
在 HTTP/1.1 中,每个连接只能有一个活动资源,从而导致 HTTP 级别的线头 (HoL) 阻塞。 由于连接数被限制在区区 6 到 30 之间,因此资源捆绑(将较小的子资源组合成一个较大的资源)是长期以来的最佳实践。 我们今天仍然在 Webpack 等打包工具中看到这一点。 类似地,资源通常内联在其他资源中(例如,关键 CSS 内联在 HTML 中)。
但是,使用 HTTP/2,单个连接会复用资源,因此您可以对文件有更多未完成的请求(换句话说,单个请求不再占用您宝贵的几个连接之一)。 这最初被解释为“我们不再需要为 HTTP/2 捆绑或内联我们的资源”。 这种方法被吹捧为更适合细粒度缓存,因为每个子资源都可以单独缓存,并且如果其中一个资源发生更改,则不需要重新下载完整的包。 这是真的,但只是在相对有限的程度上。
例如,您可以降低压缩效率,因为这样可以更好地处理更多数据。 此外,每个额外的请求或文件都有固有的开销,因为它需要由浏览器和服务器处理。 例如,与几个大文件相比,这些成本可能会增加数百个小文件。 在我们自己的早期测试中,我发现大约 40 个文件的收益严重递减。 尽管现在这些数字可能更高一些,但 HTTP/2 中的文件请求仍然不像最初预测的那样便宜。 最后,不内联资源会增加延迟成本,因为需要请求文件。 这与优先级和服务器推送问题(见下文)相结合,意味着即使在今天你仍然最好内联一些关键的 CSS。 也许有一天 Resource Bundles 提案会对此有所帮助,但目前还没有。
当然,所有这些对于 HTTP/3 也是如此。 尽管如此,我读到有人声称许多小文件会比 QUIC 更好,因为更多并发活动的独立流意味着从 HoL 阻塞删除中获得更多利润(正如我们在第 2 部分中讨论的那样)。 我认为这可能有些道理,但是,正如我们在第 2 部分中所看到的,这是一个非常复杂的问题,有很多移动参数。 我认为收益不会超过所讨论的其他成本,但需要进行更多研究。 (一个离谱的想法是将每个文件的大小精确到适合单个 QUIC 数据包,完全绕过 HoL 阻塞。我将接受任何实现资源捆绑器的初创公司的版税。;))
4. 优先级
为了能够在单个连接上下载多个文件,您需要以某种方式对它们进行多路复用。 正如第 2 部分所讨论的,在 HTTP/2 中,这种多路复用是使用其优先级系统来控制的。 这就是为什么在同一连接上请求尽可能多的资源也很重要的原因——能够正确地对它们进行优先级排序! 然而,正如我们也看到的那样,这个系统非常复杂,导致它在实践中经常被错误地使用和实施(见下图)。 反过来,这意味着 HTTP/2 的其他一些建议——例如减少捆绑,因为请求很便宜,减少服务器分片,以充分利用单个连接(见上文)——结果证明在实践。
遗憾的是,作为一个普通的 Web 开发人员,您对此无能为力,因为这主要是浏览器和服务器本身的问题。 但是,您可以尝试通过不使用太多单个文件(这将降低竞争优先级的机会)并仍然使用(有限的)分片来缓解问题。 另一种选择是使用各种影响优先级的技术,例如延迟加载、JavaScript async
和defer
以及诸如preload
之类的资源提示。 在内部,这些主要更改资源的优先级,以便它们更早或更晚地发送。 但是,这些机制可能(并且确实)存在错误。 此外,不要期望在一堆资源上preload
并让事情变得更快:如果一切突然成为高优先级,那么什么都不是! 通过使用preload
之类的东西,甚至可以很容易地延迟实际的关键资源。
正如在第 2 部分中所解释的,HTTP/3 从根本上改变了这个优先级系统的内部结构。 我们希望这意味着它的实际部署会出现更少的错误和问题,因此至少应该解决其中的一些问题。 然而,我们还不能确定,因为今天很少有 HTTP/3 服务器和客户端完全实现这个系统。 然而,优先级的基本概念不会改变。 如果不真正了解内部发生的情况,您仍然无法使用诸如preload
之类的技术,因为它可能仍然会错误地对您的资源进行优先级排序。
5. 服务器推送和首飞
服务器推送允许服务器发送响应数据而无需首先等待来自客户端的请求。 同样,这在理论上听起来很棒,并且可以用来代替内联资源(见上文)。 然而,正如第 2 部分所讨论的,由于拥塞控制、缓存、优先级和缓冲等问题,推送很难正确使用。 总的来说,除非你真的知道你在做什么,否则最好不要将它用于一般的网页加载,即使那样它也可能是一个微优化。 不过,我仍然相信它可以在 (REST) API 中占有一席之地,您可以在热连接上推送链接到 (JSON) 响应中的子资源。 对于 HTTP/2 和 HTTP/3 都是如此。
概括地说,我觉得对于 TLS 会话恢复和 0-RTT,无论是通过 TCP + TLS 还是通过 QUIC,都可以做出类似的评论。 正如第 2 部分中所讨论的,0-RTT 类似于服务器推送(因为它通常被使用),因为它试图加速页面加载的最初阶段。 然而,这意味着它在当时可以实现的目标同样受到限制(出于安全考虑,在 QUIC 中更是如此)。 同样,微优化也是您可能需要在低级别微调事物以真正从中受益的方式。 想想我曾经非常兴奋地尝试将服务器推送与 0-RTT 结合起来。
这是什么意思呢?
以上所有内容都归结为一个简单的经验法则:应用您在网上找到的大多数典型 HTTP/2 建议,但不要将它们推向极端。
下面是一些主要适用于 HTTP/2 和 HTTP/3 的具体点:
- 在关键路径上通过大约一到三个连接分片资源(除非您的用户主要在低带宽网络上),在需要时使用
preconnect
和dns-prefetch
。 - 按路径或功能或按更改频率在逻辑上捆绑子资源。 每页五到十个 JavaScript 和五到十个 CSS 资源就可以了。 内联关键 CSS 仍然是一个很好的优化。
- 谨慎使用复杂的功能,例如
preload
。 - 使用正确支持 HTTP/2 优先级的服务器。 对于 HTTP/2,我推荐 H2O。 Apache 和 NGINX 大部分都可以(尽管可以做得更好),而对于 HTTP/2,应避免使用 Node.js。 对于 HTTP/3,目前还不太清楚(见下文)。
- 确保在您的 HTTP/2 Web 服务器上启用了 TLS 1.3。
如您所见,虽然远非简单,但为 HTTP/3(和 HTTP/2)优化页面并不是火箭科学。 然而,更困难的是正确设置 HTTP/3 服务器、客户端和工具。
服务器和网络
您现在可能已经了解,QUIC 和 HTTP/3 是相当复杂的协议。 从头开始实施它们将涉及阅读(和理解!)分布在七个以上文档中的数百页。 幸运的是,五年多来,多家公司一直致力于开源 QUIC 和 HTTP/3 实现,因此我们有几个成熟稳定的选项可供选择。
一些最重要和最稳定的包括以下内容:
语言 | 执行 |
---|---|
Python | 艾奥奎克 |
走 | 快走 |
锈 | 乳蛋饼 (Cloudflare)、Quinn、Neqo (Mozilla) |
C 和 C++ | mvfst (Facebook), MsQuic, (Microsoft), (Google), ngtcp2, LSQUIC (Litespeed), picoquic, quicly (Fastly) |
然而,这些实现中的许多(也许是大多数)主要处理 HTTP/3 和 QUIC 的东西。 它们本身并不是真正成熟的 Web 服务器。 当涉及到您的典型服务器(想想 NGINX、Apache、Node.js)时,由于几个原因,事情变得有点慢。 首先,他们的开发人员从一开始就很少参与 HTTP/3,现在他们必须迎头赶上。 许多人通过在内部使用上面列出的实现之一作为库来绕过这一点,但即使是这种集成也很困难。
其次,许多服务器依赖于第三方 TLS 库,例如 OpenSSL。 这又是因为 TLS 非常复杂并且必须是安全的,所以最好重用现有的、经过验证的工作。 然而,虽然 QUIC 与 TLS 1.3 集成,但它的使用方式与 TLS 和 TCP 交互的方式大不相同。 这意味着 TLS 库必须提供特定于 QUIC 的 API,而他们的开发人员长期以来一直不愿意或缓慢地这样做。 这里的问题尤其是 OpenSSL,它推迟了对 QUIC 的支持,但它也被许多服务器使用。 这个问题变得如此严重,以至于 Akamai 决定启动 OpenSSL 的 QUIC 特定分支,称为 quictls。 尽管存在其他选项和解决方法,但 TLS 1.3 对 QUIC 的支持仍然是许多服务器的障碍,并且预计会持续一段时间。
以下是您应该能够开箱即用的完整 Web 服务器的部分列表,以及它们当前的 HTTP/3 支持:
- 阿帕奇
目前尚不清楚支持。 什么都没有宣布。 它可能还需要 OpenSSL。 (请注意,有一个 Apache Traffic Server 实现。) - NGINX
这是一个自定义实现。 这是相对较新的,仍然是高度实验性的。 预计将在 2021 年底合并到 NGINX 主线。这是相对较新的,仍处于高度试验阶段。 请注意,还有一个补丁可以在 NGINX 上运行 Cloudflare 的 quiche 库,目前它可能更稳定。 - 节点.js
这在内部使用 ngtcp2 库。 它被 OpenSSL 的进展所阻止,尽管他们计划切换到 QUIC-TLS 分支以更快地工作。 - IIS
目前尚不清楚是否支持,也没有宣布任何消息。 不过,它可能会在内部使用 MsQuic 库。 - 超级玉米
这集成了 aioquic,具有实验支持。 - 球童
这使用了 quic-go,得到了完全的支持。 - 水
这使用很快,完全支持。 - 光速
这使用了 LSQUIC,并得到了全面支持。
请注意一些重要的细微差别:
- 即使是“全力支持”也意味着“尽其所能”,不一定是“生产就绪”。 例如,许多实现还不完全支持连接迁移、0-RTT、服务器推送或 HTTP/3 优先级。
- 其他未列出的服务器,例如 Tomcat,(据我所知)尚未发布任何公告。
- 在列出的 Web 服务器中,只有 Litespeed、Cloudflare 的 NGINX 补丁和 H2O 是由密切参与 QUIC 和 HTTP/3 标准化的人员制作的,因此这些服务器最有可能在早期工作得最好。
如您所见,服务器环境尚未完全成熟,但肯定已经有设置 HTTP/3 服务器的选项。 然而,简单地运行服务器只是第一步。 配置它和网络的其余部分更加困难。
网络配置
如第 1 部分所述,QUIC 在 UDP 协议之上运行,以使其更易于部署。 然而,这主要只是意味着大多数网络设备都可以解析和理解 UDP。 可悲的是,这并不意味着 UDP 是普遍允许的。 由于 UDP 经常用于攻击,并且除了 DNS 之外对日常工作并不重要,因此许多(企业)网络和防火墙几乎完全阻止了该协议。 因此,可能需要明确允许 UDP 进出您的 HTTP/3 服务器。 QUIC 可以在任何 UDP 端口上运行,但最常见的是端口 443(通常也用于 TCP 上的 HTTPS)。
但是,许多网络管理员不想只允许 UDP 批发。 相反,他们会特别希望允许 QUIC over UDP。 问题在于,正如我们所见,QUIC 几乎是完全加密的。 这包括 QUIC 级别的元数据,例如数据包编号,还包括指示连接关闭的信号。 对于 TCP,防火墙会主动跟踪所有这些元数据以检查预期行为。 (我们是否在数据包之前看到了完整的握手?数据包是否遵循预期的模式?有多少打开的连接?)正如我们在第 1 部分中看到的,这正是 TCP 实际上不再可进化的原因之一。 但是,由于 QUIC 的加密,防火墙可以做的这种连接级跟踪逻辑要少得多,而且它们可以检查的少数位相对复杂。
因此,许多防火墙供应商目前建议阻止 QUIC,直到他们可以更新他们的软件。 然而,即使在那之后,许多公司可能也不想允许它,因为防火墙 QUIC 支持总是比他们习惯的 TCP 功能少得多。
连接迁移功能使这一切变得更加复杂。 正如我们所见,此功能允许通过使用连接 ID (CID) 从新 IP 地址继续连接,而无需执行新的握手。 但是,对于防火墙来说,这看起来就像是在没有首先使用握手的情况下使用了新连接,这也可能是攻击者发送恶意流量。 防火墙不能只使用 QUIC CID,因为它们也会随着时间的推移而变化以保护用户的隐私! 因此,服务器将需要与防火墙就预期的 CID 进行通信,但这些东西都不存在。
对于大规模设置的负载均衡器也有类似的担忧。 这些机器将传入连接分布在大量后端服务器上。 当然,一个连接的流量必须始终路由到同一个后端服务器(其他人不知道如何处理它!)。 对于 TCP,这可以简单地基于 4 元组来完成,因为它永远不会改变。 但是,使用 QUIC 连接迁移,这不再是一种选择。 同样,服务器和负载均衡器需要以某种方式就选择哪些 CID 达成一致,以允许确定性路由。 然而,与防火墙配置不同的是,已经有一个建议来设置它(尽管这远未得到广泛实施)。
最后,还有其他更高级别的安全考虑,主要围绕 0-RTT 和分布式拒绝服务 (DDoS) 攻击。 正如第 2 部分中所讨论的,QUIC 已经针对这些问题提供了很多缓解措施,但理想情况下,它们还将在网络上使用额外的防御线。 例如,代理或边缘服务器可能会阻止某些 0-RTT 请求到达实际后端,以防止重放攻击。 或者,为了防止反射攻击或仅发送第一个握手包然后停止回复的 DDoS 攻击(在 TCP 中称为 SYN 洪水),QUIC 包含重试功能。 这允许服务器验证它是一个行为良好的客户端,而不必同时保持任何状态(相当于 TCP SYN cookie)。 当然,这个重试过程最好发生在后端服务器之前的某个地方——例如,在负载均衡器上。 不过,这同样需要额外的配置和通信来设置。
这些只是网络和系统管理员使用 QUIC 和 HTTP/3 时最突出的问题。 还有几个,其中一些我已经谈过了。 QUIC RFC 还有两个单独的随附文档,讨论了这些问题及其可能的(部分)缓解措施。
这是什么意思呢?
HTTP/3 和 QUIC 是依赖大量内部机制的复杂协议。 尽管您已经有一些选项可以在后端部署新协议,但并非所有这些都已准备好迎接黄金时段。 然而,最重要的服务器和底层库(例如 OpenSSL)可能需要几个月甚至几年的时间才能得到更新。
即使这样,正确配置服务器和其他网络中介,以便可以以安全和最佳方式使用协议,在更大规模的设置中也并非易事。 您将需要一个优秀的开发和运营团队来正确地进行这种过渡。
因此,尤其是在早期,最好依靠大型托管公司或 CDN为您设置和配置协议。 正如第 2 部分中所讨论的,这就是 QUIC 最有可能获得回报的地方,使用 CDN 是您可以做的关键性能优化之一。 我个人会推荐使用 Cloudflare 或 Fastly,因为它们密切参与了标准化过程,并且将拥有最先进和经过良好调整的实现。
客户和 QUIC 发现
到目前为止,我们已经考虑了对新协议的服务器端和网络内支持。 然而,在客户端方面也需要克服几个问题。
在开始之前,让我们先从一些好消息开始:大多数流行的浏览器已经(实验性)支持 HTTP/3! 具体来说,在撰写本文时,以下是支持状态(另请参见 caniuse.com):
- Google Chrome(版本 91+) :默认启用。
- Mozilla Firefox(89+ 版) :默认启用。
- Microsoft Edge(版本 90+) :默认启用(内部使用 Chromium)。
- Opera(版本 77+) :默认启用(内部使用 Chromium)。
- Apple Safari(版本 14) :在手动标志后面。 将在版本 15 中默认启用,该版本目前处于技术预览阶段。
- 其他浏览器:目前还没有我知道的信号(尽管其他在内部使用 Chromium 的浏览器,例如 Brave,理论上也可以开始启用它)。
注意一些细微差别:
- 大多数浏览器都在逐步推出,因此并非所有用户都会从一开始就默认启用 HTTP/3 支持。 这样做是为了限制一个被忽视的错误可能影响许多用户或服务器部署过载的风险。 因此,即使在最近的浏览器版本中,您也很有可能不会默认获得 HTTP/3,并且必须手动启用它。
- 与服务器一样,HTTP/3 支持并不意味着此时所有功能都已实现或正在使用。 特别是,0-RTT、连接迁移、服务器推送、动态 QPACK 标头压缩和 HTTP/3 优先级可能仍然缺失、禁用、谨慎使用或配置不当。
- 如果您想在浏览器之外使用客户端 HTTP/3(例如,在您的本机应用程序中),则必须集成上面列出的库之一或使用 cURL。 Apple 将很快为其在 macOS 和 iOS 上的内置网络库带来原生 HTTP/3 和 QUIC 支持,Microsoft 正在将 QUIC 添加到 Windows 内核及其 .NET 环境中,但(据我所知)还没有类似的原生支持宣布适用于 Android 等其他系统。
Alt-Svc
即使您已经设置了兼容 HTTP/3 的服务器并且正在使用更新的浏览器,您可能会惊讶地发现HTTP/3 实际上并没有被一致地使用。 要理解为什么,让我们假设您暂时是浏览器。 您的用户已请求您导航到example.com
(您以前从未访问过的网站),并且您已使用 DNS 将其解析为 IP。 您向该 IP 发送一个或多个 QUIC 握手数据包。 现在有几件事可能会出错:
- 服务器可能不支持 QUIC。
- 中间网络或防火墙之一可能会完全阻止 QUIC 和/或 UDP。
- 握手包可能在传输过程中丢失。
但是,您怎么知道发生了这些问题中的哪一个? 在这三种情况下,您将永远不会收到对握手数据包的回复。 你唯一能做的就是等待,希望回复可能仍然到来。然后,在等待一段时间(超时)之后,你可能会认为 HTTP/3 确实存在问题。 此时,您将尝试打开与服务器的 TCP 连接,希望 HTTP/2 或 HTTP/1.1 能够正常工作。
如您所见,这种方法可能会引入重大延迟,尤其是在许多服务器和网络尚不支持 QUIC 的最初几年。 一个简单但幼稚的解决方案就是同时打开 QUIC 和 TCP 连接,然后使用先完成的握手。 这种方法被称为“连接赛车”或“快乐眼球”。 虽然这当然是可能的,但它确实有相当大的开销。 即使丢失的连接几乎立即关闭,它仍然会占用客户端和服务器上的一些内存和 CPU 时间(尤其是在使用 TLS 时)。 最重要的是,这种方法还存在其他问题,涉及 IPv4 与 IPv6 网络以及之前讨论的重放攻击(我的演讲将更详细地介绍)。
因此,对于 QUIC 和 HTTP/3,浏览器更愿意安全地使用它,并且只有在知道服务器支持它的情况下才尝试 QUIC 。 因此,第一次联系新服务器时,浏览器将仅通过 TCP 连接使用 HTTP/2 或 HTTP/1.1。 然后服务器可以让浏览器知道它也支持 HTTP/3 进行后续连接。 这是通过在通过 HTTP/2 或 HTTP/1.1 发回的响应上设置特殊的 HTTP 标头来完成的。 此标头称为Alt-Svc
,代表“替代服务”。 Alt-Svc
可用于让浏览器知道某个服务也可通过另一台服务器(IP 和/或端口)访问,但它也允许指示替代协议。 这可以在下面的图 1 中看到。
在收到指示 HTTP/3 支持的有效Alt-Svc
标头后,浏览器将缓存此标头并尝试从那时起建立 QUIC 连接。 一些客户端会尽快执行此操作(即使在初始页面加载期间 - 见下文),而其他客户端将等到现有 TCP 连接关闭。 这意味着浏览器只有在首先通过 HTTP/2 或 HTTP/1.1 下载了至少一些资源之后才会使用 HTTP/3 。 即使这样,也不是一帆风顺。 浏览器现在知道服务器支持 HTTP/3,但这并不意味着中间网络不会阻止它。 因此,在实践中仍然需要连接竞赛。 因此,如果网络以某种方式延迟了 QUIC 握手,您可能仍然会使用 HTTP/2。 此外,如果 QUIC 连接连续建立几次失败,一些浏览器会将Alt-Svc
缓存条目放入拒绝名单一段时间,而不是尝试 HTTP/3。 因此,如果事情发生了,手动清除浏览器的缓存会很有帮助,因为这也应该清空Alt-Svc
绑定。 最后, Alt-Svc
已被证明会带来一些严重的安全风险。 出于这个原因,一些浏览器对例如可以使用哪些端口提出了额外的限制(在 Chrome 中,您的 HTTP/2 和 HTTP/3 服务器需要都在低于 1024 的端口上,或者都在高于或等于的端口上到 1024,否则Alt-Svc
将被忽略)。 所有这些逻辑在浏览器之间变化和发展很大,这意味着获得一致的 HTTP/3 连接可能很困难,这也使得测试新设置变得具有挑战性。
正在进行的工作是在一定程度上改进这个两步Alt-Svc
过程。 这个想法是使用称为 SVCB 和 HTTPS 的新 DNS 记录,它们将包含类似于Alt-Svc
中的信息。 因此,客户端可以在 DNS 解析步骤中发现服务器支持 HTTP/3,这意味着它可以从第一个页面加载开始尝试 QUIC,而不必首先通过 HTTP/2 或 HTTP/1.1。 有关此和Alt-Svc
的更多信息,请参阅去年关于 HTTP/2 的 Web Almanac 章节。
如您所见, Alt-Svc
和 HTTP/3 发现过程为您已经具有挑战性的 QUIC 服务器部署增加了一层复杂性,因为:
- 您将始终需要将 HTTP/3 服务器部署在 HTTP/2 和/或 HTTP/1.1 服务器旁边;
- 您将需要配置您的 HTTP/2 和 HTTP/1.1 服务器以在其响应中设置正确的
Alt-Svc
标头。
虽然这在生产级设置中应该是可以管理的(例如,因为单个 Apache 或 NGINX 实例可能会同时支持所有三个 HTTP 版本),但在(本地)测试集中它可能更烦人 - ups (我已经可以看到自己忘记添加Alt-Svc
标头或将它们弄乱了)。 这个问题因(当前)缺乏浏览器错误日志和 DevTools 指标而变得更加复杂,这意味着弄清楚为什么设置不工作可能很困难。
其他问题
好像这还不够,另一个问题将使本地测试更加困难: Chrome 让您很难为 QUIC 使用自签名 TLS 证书。 这是因为公司经常使用非官方 TLS 证书来解密其员工的 TLS 流量(例如,这样他们就可以让防火墙扫描加密流量内部)。 但是,如果公司开始使用 QUIC 来做这件事,我们将再次拥有自定义的中间盒实现,它们对协议做出自己的假设。 这可能会导致他们在未来可能会破坏协议支持,而这正是我们一开始就试图通过如此广泛地加密 QUIC 来防止的! 因此,Chrome 对此采取了非常固执的立场:如果您没有使用官方 TLS 证书(由 Chrome 信任的证书颁发机构或根证书签名,例如 Let's Encrypt),那么您不能使用 QUIC 。 遗憾的是,这还包括自签名证书,通常用于本地测试设置。
通过使用每个开发人员的证书(尽管设置它可能很乏味),仍然可以使用一些奇怪的命令行标志来绕过它(因为常见的--ignore-certificate-errors
还不适用于 QUIC), or by setting up the real certificate on your development PC (but this is rarely an option for big teams because you would have to share the certificate's private key with each developer). Finally, while you can install a custom root certificate, you would then also need to pass both the --origin-to-force-quic-on
and --ignore-certificate-errors-spki-list
flags when starting Chrome (see below). Luckily, for now, only Chrome is being so strict, and hopefully, its developers will loosen their approach over time.
If you are having problems with your QUIC set-up from inside a browser, it's best to first validate it using a tool such as cURL. cURL has excellent HTTP/3 support (you can even choose between two different underlying libraries) and also makes it easier to observe Alt-Svc
caching logic.
这是什么意思呢?
Next to the challenges involved with setting up HTTP/3 and QUIC on the server-side, there are also difficulties in getting browsers to use the new protocols consistently. This is due to a two-step discovery process involving the Alt-Svc
HTTP header and the fact that HTTP/2 connections cannot simply be “upgraded” to HTTP/3, because the latter uses UDP.
Even if a server supports HTTP/3, however, clients (and website owners!) need to deal with the fact that intermediate networks might block UDP and/or QUIC traffic. As such, HTTP/3 will never completely replace HTTP/2 . In practice, keeping a well-tuned HTTP/2 set-up will remain necessary both for first-time visitors and visitors on non-permissive networks. Luckily, as we discussed, there shouldn't be many page-level changes between HTTP/2 and HTTP/3, so this shouldn't be a major headache.
What could become a problem, however, is testing and verifying whether you are using the correct configuration and whether the protocols are being used as expected. This is true in production, but especially in local set-ups. As such, I expect that most people will continue to run HTTP/2 (or even HTTP/1.1) development servers , switching only to HTTP/3 in a later deployment stage. Even then, however, validating protocol performance with the current generation of tools won't be easy.
Tools and Testing
As was the case with many major servers, the makers of the most popular web performance testing tools have not been keeping up with HTTP/3 from the start. Consequently, few tools have dedicated support for the new protocol as of July 2021, although they support it to a certain degree.
谷歌灯塔
First, there is the Google Lighthouse tool suite. While this is an amazing tool for web performance in general, I have always found it somewhat lacking in aspects of protocol performance. This is mostly because it simulates slow networks in a relatively unrealistic way, in the browser (the same way that Chrome's DevTools handle this). While this approach is quite usable and typically “good enough” to get an idea of the impact of a slow network, testing low-level protocol differences is not realistic enough. Because the browser doesn't have direct access to the TCP stack, it still downloads the page on your normal network, and it then artificially delays the data from reaching the necessary browser logic. This means, for example, that Lighthouse emulates only delay and bandwidth, but not packet loss (which, as we've seen, is a major point where HTTP/3 could potentially differ from HTTP/2). Alternatively, Lighthouse uses a highly advanced simulation model to guesstimate the real network impact, because, for example, Google Chrome has some complex logic that tweaks several aspects of a page load if it detects a slow network. This model has, to the best of my knowledge, not been adjusted to handle IETF QUIC or HTTP/3 yet. As such, if you use Lighthouse today for the sole purpose of comparing HTTP/2 and HTTP/3 performance, then you are likely to get erroneous or oversimplified results, which could lead you to wrong conclusions about what HTTP/3 can do for your website in practice. The silver lining is that, in theory, this can be improved massively in the future, because the browser does have full access to the QUIC stack, and thus Lighthouse could add much more advanced simulations (including packet loss!) for HTTP/3 down the line. For now, though, while Lighthouse can, in theory, load pages over HTTP/3, I would recommend against it.
WebPageTest
Secondly, there is WebPageTest. This amazing project lets you load pages over real networks from real devices across the world, and it also allows you to add packet-level network emulation on top, including aspects such as packet loss! As such, WebPageTest is conceptually in a prime position to be used to compare HTTP/2 and HTTP/3 performance. However, while it can indeed already load pages over the new protocol, HTTP/3 has not yet been properly integrated into the tooling or visualizations . For example, there are currently no easy ways to force a page load over QUIC, to easily view how Alt-Svc
was actually used, or even to see QUIC handshake details. In some cases, even seeing whether a response used HTTP/3 or HTTP/2 can be challenging. Still, in April, I was able to use WebPageTest to run quite a few tests on facebook.com
and see HTTP/3 in action, which I'll go over now.
First, I ran a default test for facebook.com
, enabling the “repeat view” option. As explained above, I would expect the first page load to use HTTP/2, which will include the Alt-Svc
response header. As such, the repeat view should use HTTP/3 from the start. In Firefox version 89, this is more or less what happens. However, when looking at individual responses, we see that even during the first page load, Firefox will switch to using HTTP/3 instead of HTTP/2 ! As you can see in figure 2, this happens from the 20th resource onwards. This means that Firefox establishes a new QUIC connection as soon as it sees the Alt-Svc
header, and it switches to it once it succeeds. If you scroll down to the connection view, it also seems to show that Firefox even opened two QUIC connections: one for credentialed CORS requests and one for no-CORS requests. This would be expected because, as we discussed above, even for HTTP/2 and HTTP/3, browsers will open multiple connections due to security concerns. However, because WebPageTest doesn't provide more details in this view, it's difficult to confirm without manually digging through the data. Looking at the repeat view (second visit), it starts by directly using HTTP/3 for the first request, as expected.
Next, for Chrome, we see similar behavior for the first page load, although here Chrome already switches on the 10th resource, much earlier than Firefox. It's a bit more unclear here whether it switches as soon as possible or only when a new connection is needed (for example, for requests with different credentials), because, unlike for Firefox, the connection view also doesn't seem to show multiple QUIC connections. For the repeat view, we see some weirder things. Unexpectedly, Chrome starts off using HTTP/2 there as well , switching to HTTP/3 only after a few requests! I performed a few more tests on other pages as well, to confirm that this is indeed consistent behaviour. This could be due to several things: It might just be Chrome's current policy, it might be that Chrome “raced” a TCP and QUIC connection and TCP won initially, or it might be that the Alt-Svc
cache from the first view was unused for some reason. At this point, there is, sadly, no easy way to determine what the problem really is (and whether it can even be fixed).
Another interesting thing I noticed here is the apparent connection coalescing behavior. As discussed above, both HTTP/2 and HTTP/3 can reuse connections even if they go to other hostnames, to prevent downsides from hostname sharding. However, as shown in figure 3, WebPageTest reports that, for this Facebook load, connection coalescing is used over HTTP/3 forfacebook.com
andfbcdn.net
, but not over HTTP/2 (as Chrome opens a secondary connection for the second domain). I suspect this is a bug in WebPageTest, however, becausefacebook.com
andfbcnd.net
resolve to different IPs and, as such, can't really be coalesced.
The figure also shows that some key QUIC handshake information is missing from the current WebPageTest visualization.
Note : As we see, getting “real” HTTP/3 going can be difficult sometimes. Luckily, for Chrome specifically, we have additional options we can use to test QUIC and HTTP/3, in the form of command-line parameters.
On the bottom of WebPageTest's “Chromium” tab, I used the following command-line options:
--enable-quic --quic-version=h3-29 --origin-to-force-quic-on=www.facebook.com:443,static.xx.fbcdn.net:443
The results from this test show that this indeed forces a QUIC connection from the start, even in the first view, thus bypassing the Alt-Svc
process. Interestingly, you will notice I had to pass two hostnames to --origin-to-force-quic-on
. In the version where I didn't, Chrome, of course, still first opened an HTTP/2 connection to the fbcnd.net
domain, even in the repeat view. As such, you'll need to manually indicate all QUIC origins in order for this to work !
We can see even from these few examples that a lot of stuff is going on with how browsers actually use HTTP/3 in practice. It seems they even switch to the new protocol during the initial page load, abandoning HTTP/2 either as soon as possible or when a new connection is needed. As such, it's difficult not only getting a full HTTP/3 load, but also getting a pure HTTP/2 load on a set-up that supports both ! Because WebPageTest doesn't show much HTTP/3 or QUIC metadata yet, figuring out what's going on can be challenging, and you can't trust the tools and visualizations at face value either.
So, if you use WebPageTest, you'll need to double-check the results to make sure which protocols were actually used. Consequently, I think this means that it's too early to really test HTTP/3 performance at this time (and especially too early to compare it to HTTP/2). This belief is strengthened by the fact that not all servers and clients have implemented all protocol features yet. Due to the fact that WebPageTest doesn't yet have easy ways of showing whether advanced aspects such as 0-RTT were used, it will be tricky to know what you're actually measuring. This is especially true for the HTTP/3 prioritization feature, which isn't implemented properly in all browsers yet and which many servers also lack full support for. Because prioritization can be a major aspect driving web performance, it would be unfair to compare HTTP/3 to HTTP/2 without making sure that at least this feature works properly (for both protocols!). This is just one aspect, though, as my research shows how big the differences between QUIC implementations can be. If you do any comparison of this sort yourself (or if you read articles that do), make 100% sure that you've checked what's actually going on .
Finally, also note that other higher-level tools (or data sets such as the amazing HTTP Archive) are often based on WebPageTest or Lighthouse (or use similar methods), so I suspect that most of my comments here will be widely applicable to most web performance tooling. Even for those tool vendors announcing HTTP/3 support in the coming months, I would be a bit skeptical and would validate that they're actually doing it correctly. For some tools, things are probably even worse, though; for example, Google's PageSpeed Insights only got HTTP/2 support this year, so I wouldn't wait for HTTP/3 arriving anytime soon.
Wireshark、qlog 和 qvis
正如上面的讨论所示,此时仅使用 Lighthouse 或 WebPageTest 来分析 HTTP/3 行为可能会很棘手。 幸运的是,可以使用其他较低级别的工具来帮助解决此问题。 首先,出色的 Wireshark 工具对 QUIC 具有高级支持,它也可以实验性地剖析 HTTP/3。 这允许您观察哪些 QUIC 和 HTTP/3 数据包实际上正在通过网络传输。 但是,为了使其工作,您需要获取给定连接的 TLS 解密密钥,大多数实现(包括 Chrome 和 Firefox)允许您使用SSLKEYLOGFILE
环境变量来提取。 虽然这对某些事情很有用,但真正弄清楚发生了什么,尤其是对于更长的连接,可能需要大量的手动工作。 您还需要对协议的内部运作有相当深入的了解。
幸运的是,还有第二种选择,qlog 和 qvis。 qlog 是一种基于 JSON 的日志格式,专门用于 QUIC 和 HTTP/3,大多数 QUIC 实现都支持它。 qlog 不是查看通过线路传输的数据包,而是直接在客户端和服务器上捕获此信息,这允许它包含一些附加信息(例如,拥塞控制详细信息)。 通常,您可以在使用QLOGDIR
环境变量启动服务器和客户端时触发 qlog 输出。 (请注意,在 Firefox 中,您需要设置network.http.http3.enable_qlog
首选项。Apple 设备和 Safari 使用QUIC_LOG_DIRECTORY
尚不支持 qlog。)
然后可以将这些 qlog 文件上传到位于 qvis.quictools.info 的 qvis 工具套件。 在那里,您将获得许多高级交互式可视化效果,可以更轻松地解释 QUIC 和 HTTP/3 流量。 qvis 还支持上传 Wireshark 数据包捕获( .pcap
文件),并且它对 Chrome 的 netlog 文件具有实验性支持,因此您还可以分析 Chrome 的行为。 关于 qlog 和 qvis 的完整教程超出了本文的范围,但可以在教程形式、论文形式甚至脱口秀形式中找到更多详细信息。 你也可以直接问我,因为我是 qlog 和 qvis 的主要实现者。 ;)
但是,我并不认为这里的大多数读者都应该使用 Wireshark 或 qvis,因为它们是相当低级的工具。 尽管如此,由于目前我们几乎没有其他选择,我强烈建议您不要在不使用此类工具的情况下广泛测试 HTTP/3 性能,以确保您真正了解网络上正在发生的事情以及您所看到的是否真的由协议的内部结构,而不是其他因素。
这是什么意思呢?
正如我们所见,通过 QUIC 设置和使用 HTTP/3 可能是一件复杂的事情,而且很多事情都可能出错。 遗憾的是,没有好的工具或可视化可以在适当的抽象级别上公开必要的细节。 这使得大多数开发人员很难评估 HTTP/3 目前可以给他们的网站带来的潜在好处,甚至很难验证他们的设置是否按预期工作。
仅依赖高级指标是非常危险的,因为这些指标可能会受到多种因素的影响(例如不切实际的网络仿真、客户端或服务器上缺乏功能、仅使用部分 HTTP/3 等)。 即使一切都做得更好,正如我们在第 2 部分中看到的那样,在大多数情况下,HTTP/2 和 HTTP/3 之间的差异可能相对较小,这使得从高层获取必要信息变得更加困难没有目标 HTTP/3 支持的工具。
因此,我建议将 HTTP/2 与 HTTP/3 性能测量单独放置几个月,并专注于确保我们的服务器端设置按预期运行。 为此,将 WebPageTest 与谷歌浏览器的命令行参数结合使用是最简单的,并回退到 curl 以解决潜在问题——这是目前我能找到的最一致的设置。
结论和要点
亲爱的读者,如果您已阅读完整的三部分系列并在这里完成,我向您致敬! 即使您只阅读了几个部分,我也要感谢您对这些令人兴奋的新协议的兴趣。 现在,我将总结本系列的主要内容,为未来几个月和一年提供一些重要建议,最后为您提供一些额外资源,以供您了解更多信息。
概括
首先,在第 1 部分中,我们讨论了之所以需要 HTTP/3,主要是因为新的底层 QUIC 传输协议。 QUIC 是 TCP 的精神继承者,它集成了所有最佳实践以及 TLS 1.3。 这主要是因为 TCP,由于其在中间盒中无处不在的部署和集成,已经变得太不灵活而无法发展。 QUIC 使用 UDP 和几乎完全加密意味着我们(希望)将来只需要更新端点即可添加新功能,这应该更容易。 然而,QUIC 也增加了一些有趣的新功能。 首先,QUIC 的组合传输和加密握手比 TCP + TLS 更快,并且可以很好地利用 0-RTT 特性。 其次,QUIC 知道它正在承载多个独立的字节流,并且可以更智能地处理丢失和延迟,从而减轻线头阻塞问题。 第三,QUIC 连接可以通过使用连接 ID 标记每个数据包来让用户迁移到不同的网络(称为连接迁移)。 最后,QUIC 灵活的数据包结构(使用帧)使其更加高效,但在未来也更加灵活和可扩展。 总之,很明显QUIC 是下一代传输协议,将在未来很多年使用和扩展。
其次,在第 2 部分中,我们对这些新功能进行了一些批判性的研究,尤其是它们对性能的影响。 首先,我们看到 QUIC 使用 UDP 并没有神奇地让它更快(也不是更慢),因为 QUIC 使用与 TCP 非常相似的拥塞控制机制来防止网络过载。 其次,更快的握手和 0-RTT 是更多的微优化,因为它们实际上只比优化的 TCP + TLS 堆栈快一个往返,而 QUIC 真正的 0-RTT 进一步受到一系列安全问题的影响,这些问题可以限制它的用处。 第三,连接迁移实际上只在少数特定情况下需要,它仍然意味着重置发送速率,因为拥塞控制不知道新网络可以处理多少数据。 第四,QUIC 的行头阻塞去除的有效性严重取决于流数据的复用和优先级。 从丢包中恢复的最佳方法似乎对网页加载性能的一般用例有害,反之亦然,尽管需要更多的研究。 第五,QUIC 发送数据包的速度很容易比 TCP + TLS 慢,因为 UDP API 不太成熟,并且 QUIC 单独加密每个数据包,尽管这可以在很大程度上及时缓解。 第六,HTTP/3 本身并没有真正带来任何重大的新性能特性,而是主要对已知 HTTP/2 特性的内部进行了重新设计和简化。 最后,QUIC 允许的一些最令人兴奋的与性能相关的功能(多路径、不可靠数据、WebTransport、前向纠错等)不是核心 QUIC 和 HTTP/3 标准的一部分,而是提出的扩展,将采用还有一些时间可用。 总而言之,这意味着QUIC 可能不会对高速网络上的用户提高性能,但主要对慢速和不稳定网络上的用户很重要。
最后,在第 3 部分中,我们研究了如何实际使用和部署 QUIC 和 HTTP/3 。 首先,我们看到从 HTTP/2 中学到的大多数最佳实践和经验教训应该只适用于 HTTP/3。 无需更改捆绑或内联策略,也无需整合或分片服务器场。 服务器推送仍然不是最好的使用功能, preload
同样可以成为一个强大的脚枪。 其次,我们已经讨论过,现成的 Web 服务器包可能需要一段时间才能提供完整的 HTTP/3 支持(部分原因是 TLS 库支持问题),尽管有很多开源选项可供早期采用者使用,并且几个主要的 CDN 都有成熟的产品。 第三,很明显大多数主流浏览器都有(基本的)HTTP/3 支持,甚至默认启用。 但是,他们在实际使用 HTTP/3 及其新功能的方式和时间方面存在重大差异,因此了解他们的行为可能具有挑战性。 第四,我们已经讨论过,由于 Lighthouse 和 WebPageTest 等流行工具缺乏对 HTTP/3 的明确支持,这使情况变得更糟,这使得目前将 HTTP/3 性能与 HTTP/2 和 HTTP/1.1 进行比较尤其困难。 总之, HTTP/3 和 QUIC 可能还没有完全准备好迎接黄金时段,但它们很快就会成为.
建议
从上面的总结来看,我似乎在强烈反对使用 QUIC 或 HTTP/3。 然而,这与我想表达的观点完全相反。
首先,正如在第 2 部分末尾所讨论的,即使您的“普通”用户可能不会获得重大的性能提升(取决于您的目标市场),但您的大部分受众可能会看到令人印象深刻的改进。 0-RTT 可能只节省一次往返,但对于某些用户来说,这仍然意味着几百毫秒。 连接迁移可能无法维持持续快速的下载,但它肯定会帮助人们试图在高速列车上获取该 PDF。 电缆上的数据包丢失可能是突发性的,但无线链路可能会从 QUIC 的线头阻塞移除中受益更多。 更重要的是,这些用户通常会遇到产品性能最差的情况,因此受产品影响最大。 如果您想知道为什么这很重要,请阅读 Chris Zacharias 著名的网络性能轶事。
其次, QUIC 和 HTTP/3 只会随着时间的推移变得越来越好。 版本 1 专注于完成基本协议,为以后保留更高级的性能特性。 因此,我觉得现在开始投资协议是值得的,以确保您可以使用它们以及新功能在它们可用时达到最佳效果。 鉴于协议及其部署方面的复杂性,最好给自己一些时间来熟悉它们的怪癖。 即使您还不想亲自动手,一些主要的 CDN 提供商也提供成熟的“翻转开关”HTTP/3 支持(尤其是 Cloudflare 和 Fastly)。 如果您使用的是 CDN,我很难找到不尝试的理由(如果您关心性能,那么您真的应该这样做)。
因此,虽然我不会说尽快开始使用 QUIC 和 HTTP/3至关重要,但我确实觉得已经有了很多好处,而且它们只会在未来增加。
延伸阅读
虽然这是一篇很长的文章,但遗憾的是,它实际上只是触及了 QUIC 和 HTTP/3 等复杂协议的技术表面。
您将在下面找到用于继续学习的其他资源列表,或多或少按技术深度的升序排列:
- “HTTP/3 解释”,丹尼尔·斯坦伯格
这本由 cURL 的创建者编写的电子书总结了该协议。 - “HTTP/2 实战”,巴里·波拉德
这本关于 HTTP/2 的优秀全能书有可重用的建议和关于 HTTP/3 的部分。 - @programmingart,推特
我的推文主要针对 QUIC、HTTP/3 和 Web 性能(包括新闻)。 例如,请参阅我最近关于 QUIC 功能的主题。 - “YouTube”,罗宾·马克思
我的 10 多次深入讨论涵盖了协议的各个方面。 - “Cloudlare 博客”
这是一家同时运行 CDN 的公司的主要产品。 - “快速博客”
该博客在更广泛的背景下对技术方面进行了出色的讨论。 - QUIC,实际的 RFC
您将找到指向 IETF QUIC 和 HTTP/3 RFC 文档以及其他官方扩展的链接。 - IIJ 工程师博客:对 QUIC 功能细节的优秀深入技术解释。
- HTTP/3 和 QUIC 学术论文,Robin Marx
我的研究论文涵盖了流多路复用和优先级划分、工具和实现差异。 - QUIPS、EPIQ 2018 和 EPIQ 2020
这些来自学术研讨会的论文包含对协议的安全性、性能和扩展的深入研究。
有了这个,亲爱的读者,我希望你对这个勇敢的新世界有了很大的了解。 我总是乐于接受反馈,所以请让我知道你对这个系列的看法!
- 第 1 部分:HTTP/3 历史和核心概念
本文主要针对 HTTP/3 和一般协议的新手,主要讨论基础知识。 - 第 2 部分:HTTP/3 性能特性
这一个更深入和技术。 已经了解基础知识的人可以从这里开始。 - 第 3 部分:实用的 HTTP/3 部署选项
本系列的第三篇文章解释了自己部署和测试 HTTP/3 所涉及的挑战。 它详细说明了如何以及是否应该更改您的网页和资源。