You are on page 1of 26

可及性 用户体验 断续器 JavaScript 性能 设计 菲格玛 壁纸

罗宾·马克思 (↦ /author/robin-marx/) / 9月 6, 2021 / 2 (↦ #comments-http3-practical-deplo

HTTP/3:实际部署选项(第 3 部分)
快 速 摘 要 ↬ 经过近五年的开发,新的HTTP / 3协议已接近其最终形

式。让我们仔细看看部署和测试HTTP / 3所涉及的挑战,以及如何以
及是否应该更改您的网站和资源。

您好,欢迎来到这个由三部分组成的系列的最后一部分,介绍新的HTTP
/ 3和QUIC协议!如果在前两部分之后 - HTTP / 3历史和核心概念 (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/)以及HTTP / 3性
能功能 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-improvements-
part2/) - 您确信开始使用新协议是一个好主意(您应该这样做!),那么
最后一部分包括您入门所需的所有知识!

首先,我们将讨论您需要对页面和资源进行哪些更改才能以最佳方式使用新协
议(这是简单的部分)。接下来,我们将介绍如何设置服务器和客户端(除非
您使用内容交付网络(CDN),否则这是困难的部分)。最后,我们将看到您
可以使用哪些工具来评估新协议的性能影响(这是几乎不可能的部分,至少现
在是这样)。

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

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


识。

第2部分:HTTP / 3性能特性 (↦
https://www.smashingmagazine.com/2021/08/http3-performance-improvements-
part2/)

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

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

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


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

对页面和资源的更改# (↦ #Changes-To-Pages-And-
Resources)

让我们从一些好消息开始:如果您已经在使用HTTP / 2,那么在迁移到HTTP /
3时,您可能不必对页面或资源进行任何更改!这是因为,正如我们在第 1 部分
(↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#why-do-we-need-http-3)和
第 2 部分中 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-improvements-
part2/#http-3-features)所解释的那样,HTTP/3 实际上更像是 HTTP/2-over-QUIC,而
这两个版本的高级功能保持不变。因此,对HTTP / 2所做的任何更改或优化仍然
适用于HTTP / 3,反之亦然。

但是,如果您仍在使用HTTP / 1.1,或者您已经忘记了向HTTP / 2的过渡,或者您


从未真正为HTTP / 2调整过内容,那么您可能想知道这些更改是什么以及为什么
需要它们。但是,即使在今天,您也很难找到一篇详细介绍细微最佳实践的好
文章。这是因为,正如我在第 1 部分的 (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/)引言中所述,早期的许
多 HTTP/2 内容都过于乐观地认为它在实践中的工作效果如何,坦率地说,其中
一些内容存在重大错误和糟糕的建议。可悲的是,许多错误信息今天仍然存
在。这是我在HTTP / 3上编写本系列文章的主要动机之一,以帮助防止这种情况
再次发生。

目前,我可以推荐的HTTP / 2的最佳一体化细致入微的来源是Barry Pollard (↦


https://www.tunetheweb.com/)的《HTTP/2 in Action》 (↦ https://www.manning.com/books/http2-
in-action)一书。但是,由于这是一个付费资源,我不希望您在这里猜测,因此我
列出了以下几个要点,以及它们与HTTP / 3的关系:

1. 单连接# (↦ #1-SINGLE-CONNECTION)

HTTP/1.1 和 HTTP/2 之间最大的区别是从 6 个并行 TCP 连接到 30 个并行 TCP 连


接切换到单个底层 TCP 连接。我们在第 2 部分中 (↦
https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/#congestion-
control)讨论了单个连接如何仍然像多个连接一样快,因为拥塞控制如何通过更多
连接导致更多或更早的数据包丢失(这抵消了其聚合更快启动的好处)。
HTTP/3 延续了这种方法,但“只是”从一个 TCP 切换到一个 QUIC 连接。这种差
异本身并没有做那么多(它主要减少了服务器端的开销),但它导致了以下大
部分问题。

2. 服务器分片和连接合并# (↦ #2-SERVER-SHARDING-AND-
CONNECTION-COALESCING)

在实践中,切换到单一连接设置非常困难,因为许多页面被分片到不同的主机
名甚至服务器(如和)。这是因为浏览器只为每个单独的主机名打开最多六个
连接,因此拥有多个主机名可以允许更多连接!如果不更改此HTTP / 1.1设置,
HTTP / 2仍将打开多个连接,从而降低其他功能(例如优先级(见下文))的实
际工作能力。 img1.example.com img2.example.com

因此,最初的建议是撤消服务器分片,并尽可能多地在单个服务器上整合资
源。HTTP/2甚至提供了一个功能,使从HTTP/1.1设置的转换更容易,称为连接合
并 (↦ https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/)。粗略地说,如果两
个主机名解析为相同的服务器IP(使用DNS)并使用类似的TLS证书,则浏览器
甚至可以跨两个主机名重用单个连接。

在实践中,连接合并可能很难正确 (↦ https://nooshu.github.io/blog/2019/12/17/http2-and-sri-
dont-always-get-on/),例如,由于涉及CORS的几个微妙的安全问题 (↦
https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/#requests-without-credentials-use-a-
separate-connection)。即使您设置正确,您仍然很容易地以两个单独的连接结束。
问题是,这并不总是坏事。首先,由于优先级和多路复用(见下文)的实现不
佳,单个连接可能比使用两个或更多连接慢 (↦
https://twitter.com/zachleat/status/1055219667894259712)。其次,由于竞争拥塞控制器,使
用过多的连接可能会导致早期数据包丢失。然而,仅使用几个(但仍然不止一
个)可以很好地平衡拥塞增长和更好的性能,特别是在高速网络上。由于这些
原因,我相信即使使用HTTP / 2,一点点分片仍然是一个好主意(例如,两到
四个连接)。事实上,我认为大多数现代HTTP / 2设置的表现都很好,因为它们
在关键路径中仍然有一些额外的连接或第三方负载。

3. 资源捆绑和内联# (↦ #3-RESOURCE-BUNDLING-AND-INLINING)

在 HTTP/1.1 中,每个连接可能只有一个活动资源,从而导致 HTTP 级别的行首


(HoL) 阻塞 (↦ https://calendar.perfplanet.com/2020/head-of-line-blocking-in-quic-and-http-3-the-
details/)。由于连接数的上限仅为 6 到 30,因此资源捆绑(将较小的子资源合并为
单个较大的资源)是一种长期的最佳做法。我们今天仍然在Webpack等捆绑器
中看到这一点。同样,资源通常内联在其他资源中(例如,关键CSS在HTML中
内联)。
但是,使用HTTP / 2,单个连接多路复用资源,因此您可以对文件有更多的未完
成请求(换句话说,单个请求不再占用您宝贵的少数连接之一)。这最初被解
释为,“我们不再需要为HTTP / 2捆绑或内联我们的资源”。这种方法被吹捧为
更适合细粒度缓存,因为每个子资源都可以单独缓存,如果其中一个子资源发
生更改,则不需要重新下载完整的捆绑包。这是事实,但只是在相对有限的程
度上。

例如,您可以降低 (↦ https://blog.khanacademy.org/forgo-js-packaging-not-so-fast/)压缩效率
(↦ https://jakearchibald.com/2021/f1-perf-part-7/#lots-of-little-resources-vs-one-big-resource),因为这
可以更好地处理更多数据。此外,每个额外的请求或文件都有固有的开销,因
为它需要由浏览器和服务器处理 (↦
https://twitter.com/yoavweiss/status/1254650804524507136)。这些成本可以加起来,例如,
与几个大文件相比,数百个小文件。在我们自己的早期测试 (↦
https://speeder.edm.uhasselt.be/webist/files/h2bestpractices_RobinMarx_WEBIST2017.pdf)中,我发
现大约40个文件的回报严重递减。虽然这些数字现在可能更高一些 (↦
https://twitter.com/youyuxi/status/1425933472871456777),但文件请求在HTTP / 2中仍然不
像最初预测的那样便宜。最后,不内联资源会增加延迟成本,因为需要请求文
件。这与优先级和服务器推送问题(见下文)相结合,意味着即使在今天,您
仍然最好内联一些关键的CSS (↦ https://calendar.perfplanet.com/2020/implementing-critical-
css-from-cms-to-cls/)。也许有一天,Resource Bundles提案 (↦
https://github.com/WICG/resource-bundles)会有所帮助,但现在还不行。

当然,对于HTTP / 3来说,所有这些都仍然是正确的。尽管如此,我还是读到
有人声称许多小文件会比QUIC更好,因为更多并发活跃的独立流意味着从HoL
阻止删除中获得更多利润(正如我们在第2部分中 (↦
https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/#head-of-line-
blocking-removal)讨论的那样)。我认为这可能有一定的道理,但是,正如我们在
第2部分中也看到的那样,这是一个非常复杂的问题,有很多移动参数。我不认
为这些好处会超过所讨论的其他成本,但需要更多的研究。(一个令人愤慨的
想法是让每个文件的大小精确到适合单个QUIC数据包,完全绕过HoL阻止。我
将接受任何实现资源捆绑器的初创公司的版税。;))
4. 优先级# (↦ #4-PRIORITIZATION)

为了能够在单个连接上下载多个文件,您需要以某种方式多路复用它们。如第 2
部分 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/#head-
of-line-blocking-removal)所述,在 HTTP/2 中,此多路复用是使用其优先级系统进行
引导的。这就是为什么在同一连接上请求尽可能多的资源很重要的原因 - 以便能
够正确地将它们彼此确定优先级!然而,正如我们也看到的那样,这个系统非
常复杂,导致它在实践中经常被糟糕地使用和实现 (↦
https://github.com/andydavies/http2-prioritization-issues)(见下图)。反过来,这意味着对
HTTP / 2的其他一些建议 - 例如减少捆绑,因为请求很便宜,以及减少服务器分
片,以充分利用单个连接(见上文) - 在实践中表现不佳。

(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/e8aef424-b7d6-
44ce-ba69-d349439fcaa5/http2-prioritization.png)

实现不当的 HTTP/2 堆栈可能导致高优先级资源(后两个)延迟到其他低优


先级下载(其余所有下载)之后。(图片来源:安迪·戴维斯 (↦
https://github.com/andydavies/http2-prioritization-issues))(大预览 (↦
https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/e8aef424-b7d6-
44ce-ba69-d349439fcaa5/http2-prioritization.png))

可悲的是,作为一个普通的Web开发人员,这是你无法做很多事情的事情,因

为它主要是浏览器和服务器本身的问题。但是,您可以通过不使用太多的单个
文件(这将降低竞争优先级的机会)和仍然使用(有限的)分片来尝试缓解此
问题。另一种选择是使用各种影响优先级的技术,例如延迟加载 (↦
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading),JavaScript 异步
和 延迟 (↦ https://addyosmani.com/blog/script-priorities/),以及资源提示(例如 预加载 (↦
https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload))。在内部,这些主要
更改资源的优先级,以便更早或更晚地发送它们。但是,这些机制可能(并且
确实)遭受错误的影响 (↦ https://bugs.chromium.org/p/chromium/issues/detail?id=788757)。
此外,不要指望在一堆资源上打耳光,让事情变得更快:如果一切都突然成为
高优先级,那么什么都不是!通过使用 预加载 之类的东西 (↦
https://www.debugbear.com/blog/rel-preload-problems),甚至很容易 (↦
https://twitter.com/programmingart/status/1351557858354225159)延迟 (↦
https://twitter.com/csswizardry/status/1349681832393109510)实际的关键资源。 preload
正如第 2 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-improvements-
part2/#head-of-line-blocking-removal)所述,HTTP/3 从根本上改变了此优先级系统的内
部结构。我们希望这意味着其实际部署中的错误和问题将大大减少,因此至少
应该解决其中的一些问题。然而,我们还不能确定,因为今天很少有HTTP / 3服
务器和客户端 (↦
https://qlog.edm.uhasselt.be/epiq/files/QUICImplementationDiversity_Marx_final_11jun2020.pdf)完全
实现这个系统。尽管如此,优先级的基本概念不会改变。如果不真正了解内部
发生的情况,您仍然无法使用诸如此类技术,因为它可能仍然会错误地确定资
源的优先级。 preload

5. 服务器推送和首次飞行# (↦ #5-SERVER-PUSH-AND-FIRST-FLIGHT)

服务器推送允许服务器发送响应数据,而无需先等待来自客户端的请求。同
样,这在理论上听起来很棒,它可以代替内联资源(见上文)。但是,如第 2
部分 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/#http-
3-features)所述,由于拥塞控制、缓存、优先级和缓冲方面的问题, (↦
https://calendar.perfplanet.com/2016/http2-push-the-details/)推送很难正确使用。总体而言,
除非您真的知道自己在做什么,否则最好不要将其用于一般网页加载,即使这
样,它也可能是一个微优化 (↦ https://twitter.com/patmeenan/status/1359337536125075460)。
不过,我仍然相信它可以在(REST)API中占有一席之地,您可以在其中在预热
连接上推送(JSON)响应中链接到的子资源 (↦ https://github.com/dunglas/vulcain)。对
于 HTTP/2 和 HTTP/3 都是如此。

为了概括一下,我觉得可以为TLS会话恢复和0-RTT做出类似的评论,无论是通
过TCP + TLS还是通过QUIC。如第 2 部分 (↦
https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/#0-rtt-
connection-set-up)所述,0-RTT 类似于服务器推送(通常使用),因为它尝试加速
页面加载的第一阶段。但是,这意味着它当时可以实现的目标同样有限(由于
安全问题,在QUIC中更是如此)。因此,微优化再次成为您可能需要在低水平
上微调事物才能真正从中受益的方式。想想我曾经非常兴奋地尝试将服务器推
送与0-RTT相结合。

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

以上所有内容都归结为一个简单的经验法则:应用您在网上找到的大多数典型
HTTP / 2建议,但不要将它们推向极端。

以下是一些具体的观点,这些观点主要适用于HTTP / 2和HTTP / 3:

01 在关键路径上大约一到三个连接上分片资源(除非您的用户大多位于低带
宽网络上),在需要时使用 预连接 和 dns 预取 (↦

https://www.smashingmagazine.com/2019/04/optimization-performance-resource-hints/)。

02 按路径或功能或每个更改频率在逻辑上捆绑子资源。每页五到十个
JavaScript和五到十个CSS资源应该没问题。内联关键CSS仍然是一个很好的
优化。

03 请谨慎使用复杂的功能,例如 。 preload

04 使用正确支持 (↦ https://github.com/andydavies/http2-prioritization-issues) HTTP/2 优先


级的服务器。对于HTTP / 2,我建议使用H2O (↦ https://github.com/h2o/h2o)。
Apache和NGINX大多是可以的(尽管可以做得更好 (↦
https://twitter.com/programmingart/status/1245397190194999297) (↦
https://blog.cloudflare.com/nginx-structural-enhancements-for-http-2-performance/)),而
Node.js对于HTTP / 2是要避免的 (↦
https://twitter.com/jasnell/status/1245410283582918657)。对于HTTP / 3,目前事情不太
清楚(见下文)。

05 确保在 HTTP/2 Web 服务器上启用了 TLS 1.3。

正如你所看到的,虽然远非简单,但针对HTTP / 3(和HTTP / 2)优化页面并不

是火箭科学。但是,更困难的是正确设置HTTP / 3服务器,客户端和工具。
服务器和网络# (↦ #Servers-And-Networks)
正如您现在可能已经了解的那样,QUIC和HTTP / 3是相当复杂的协议。从头开
始实现它们将涉及阅读(和理解!数百页,分布在七个以上的文档中 (↦
https://quicwg.org/)。幸运的是,多家公司已经在开源QUIC和HTTP / 3实现 (↦
https://github.com/quicwg/base-drafts/wiki/Implementations)上工作了五年多,因此我们有几
个成熟而稳定的选项可供选择。

一些最重要和最稳定的包括以下内容:


实现

蟒 aioquic (↦ https://github.com/aiortc/aioquic)

去 quic-go (↦ https://github.com/lucas-clemente/quic-go)

乳蛋饼 (↦ https://github.com/cloudflare/quiche)(Cloudflare),Quinn (↦
锈 https://github.com/quinn-rs/quinn),Neqo (↦ https://github.com/mozilla/neqo)
(Mozilla)

mvfst (↦ https://github.com/facebookincubator/mvfst) (Facebook),


MsQuic (↦ https://github.com/microsoft/msquic), (Microsoft),
C
(Google), ngtcp2 (↦ https://github.com/ngtcp2/ngtcp2), LSQUIC (↦

https://github.com/litespeedtech/lsquic) (Litespeed), picoquic (↦
C++
https://github.com/private-octopus/picoquic), quicly (↦
https://github.com/h2o/quicly) (Fastly)

但是,这些实现中的许多(也许是大多数)主要负责HTTP / 3和QUIC的东西;它
们本身并不是真正成熟的Web服务器。当涉及到典型的服务器(想想NGINX,
Apache,Node.js)时,由于几个原因,事情有点慢。首先,他们的开发人员中

很少有人从一开始就参与HTTP / 3,现在他们必须迎头赶上。许多人通过在内部
使用上面列出的实现之一作为库来绕过这一点,但即使是这种集成也很困难。
其次,许多服务器依赖于第三方TLS库,如OpenSSL。同样,这是因为TLS非常
复杂并且必须安全,因此最好重用现有的,经过验证的工作。但是,虽然QUIC
与TLS 1.3集成,但它的使用方式与TLS和TCP的交互方式大不相同。这意味着
TLS库必须提供特定于QUIC的API (↦ https://daniel.haxx.se/blog/2019/01/21/quic-and-missing-
apis/),而他们的开发人员长期以来一直不愿意或缓慢地做到这一点。特别是这
里的问题,是OpenSSL,它推迟了对QUIC的支持 (↦
https://www.openssl.org/blog/blog/2020/02/17/QUIC-and-OpenSSL/),但它也被许多服务器使
用。这个问题变得如此严重,以至于 Akamai 决定启动一个特定于 QUIC 的
OpenSSL 分支,称为 quictls (↦ https://github.com/quictls/openssl)。虽然存在其他选项和
解决方法 (↦ https://daniel.haxx.se/blog/2021/04/02/where-is-http-3-right-now/),但对 QUIC 的
TLS 1.3 支持仍然是许多服务器的阻碍因素,并且预计会在一段时间内保持这种
状态。

您应该能够开箱即用的完整Web服务器的部分列表,以及它们当前的HTTP / 3支
持,如下所示:

Apache

支持目前尚不清楚。什么都没有宣布。它可能还需要OpenSSL。(请注
意,有一个Apache流量服务器 (↦ https://cwiki.apache.org/confluence/display/TS/QUIC)
实现。

NGINX (↦ https://quic.nginx.org/)

这是一个自定义实现。这是相对较新的,仍然是高度实验性的。预计将于
2021年底并入主线NGINX (↦ https://www.nginx.com/blog/our-roadmap-quic-http-3-
support-nginx/)。这是相对较新的,仍然是高度实验性的。请注意,在
NGINX上也有一个补丁可以运行Cloudflare的乳蛋饼库 (↦
https://blog.cloudflare.com/experiment-with-http-3-using-nginx-and-quiche/),目前可能更
稳定。

Node.js
这在内部使用 ngtcp2 库。它被OpenSSL进度阻止了 (↦
https://github.com/nodejs/node/pull/37067),尽管他们计划切换到QUIC-TLS分叉,
以便更快地工作 (↦ https://github.com/nodejs/node/issues/38478)。

IIS

支持目前尚不明确,并且尚未宣布任何内容。不过,它可能会在内部使用
MsQuic库。

Hypercorn (↦ https://pgjones.dev/blog/http-1-2-3-2019/)

这集成了aioquic,具有实验支持。
Caddy (↦ https://ma.ttias.be/how-run-http-3-with-caddy-2/)

This 使用 quic-go,并得到全面支持。

H2O (↦ https://github.com/h2o/h2o)

这使用quicly,具有完全支持。

Litespeed (↦ https://github.com/litespeedtech/lsquic)

这使用LSQUIC,具有完全支持。

请注意一些重要的细微差别:

即使“完全支持”也意味着“目前为止”,而不一定是“生产就绪”。例如,许多
实现尚未完全支持连接迁移、0-RTT、服务器推送或 HTTP/3 优先级。

其他未列出的服务器,如Tomcat,(据我所知)尚未发布任何公告。

在列出的Web服务器中,只有Litespeed,Cloudflare的NGINX补丁和H2O是
由密切参与QUIC和HTTP / 3标准化的人制作的,因此这些最有可能在早期
工作得最好。

如您所见,服务器环境尚未完全实现,但肯定已经有设置HTTP / 3服务器的选
项。但是,简单地运行服务器只是第一步。配置它和网络的其余部分更加困
难。

网络配置# (↦ #NETWORK-CONFIGURATION)

如第 1 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#what-is-
quic)所述,QUIC 在 UDP 协议之上运行,使其更易于部署。但是,这主要意味着
大多数网络设备可以解析和理解UDP。可悲的是,这并不意味着UDP是普遍允
许的。由于UDP通常用于攻击,并且除了DNS之外,对正常的日常工作并不重
要,因此许多(企业)网络和防火墙几乎完全阻止了该协议。因此,可能需要
明确允许 UDP 进入/从 HTTP/3 服务器。QUIC 可以在任何 UDP 端口上运行,
但预计端口 443(通常也用于 TCP 上的 HTTPS)是最常见的。

但是,许多网络管理员不希望只允许 UDP 批发。相反,他们将特别希望允许


QUIC 通过 UDP。问题在于,正如我们所看到的,QUIC几乎完全加密。这包括

QUIC 级别的元数据(如数据包编号),但也包括指示连接关闭的信号。对于
TCP,防火墙会主动跟踪所有这些元数据,以检查预期行为。(在携带数据的数
据包之前,我们是否看到完全握手?数据包是否遵循预期的模式?有多少个打
开的连接?正如我们在第1部分中 (↦ https://www.smashingmagazine.com/2021/08/http3-core-
concepts-part1/#why-do-we-need-http-3)所看到的,这正是TCP不再具有实际可进化性的
原因之一。但是,由于QUIC的加密,防火墙可以少做这种连接级跟踪逻辑,
并且它们可以检查的少数位相对复杂。
因此,许多防火墙供应商目前建议阻止 QUIC,直到他们可以更新其软件。但
是,即使在那之后,许多公司可能也不想允许它,因为防火墙QUIC支持将始终
远低于他们习惯的TCP功能。

由于连接迁移功能,这一切都变得更加复杂。正如我们所看到的 (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#quic-supports-connection-
migration),此功能允许使用连接 ID (CID) 从新的 IP 地址继续连接,而无需执
行新的握手。但是,对于防火墙来说,这看起来好像在没有首先使用握手的情
况下使用新连接,这可能也是攻击者发送恶意流量。防火墙不能只使用QUIC
CID,因为它们也会随着时间的推移而变化以保护用户的隐私!因此,服务器需
要与防火墙通信,以了解预期的CID,但这些东西都不存在。

对于更大规模的设置,负载均衡器也存在类似的问题。这些计算机将传入连接
分布在大量后端服务器上。当然,一个连接的流量必须始终路由到同一后端服
务器(其他人不知道该如何处理它!对于TCP,这可以简单地基于4元组 (↦
https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/#quic-supports-connection-
migration)完成,因为这永远不会改变。但是,通过 QUIC 连接迁移,这不再是一
种选择 (↦ https://youtu.be/pq_xk_Pecu4?t=1226)。同样,服务器和负载平衡器需要以某
种方式就选择哪些 CID 达成一致,以便允许确定性路由。然而,与防火墙配置
不同的是,已经有一个建议 (↦ https://tools.ietf.org/html/draft-ietf-quic-load-balancers)来设置
它(尽管这远未得到广泛实施)。

最后,还有其他更高级别的安全注意事项,主要是围绕 0-RTT 和分布式拒绝服


务 (DDoS) 攻击。如第 2 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-
performance-improvements-part2/#0-rtt-connection-set-up)所述,QUIC 已经为这些问题提供
了相当多的缓解措施,但理想情况下,它们还将在网络上使用额外的防线。例
如,代理或边缘服务器可能会阻止某些 0-RTT 请求到达实际的后端,以防止重
播攻击 (↦ https://blog.cloudflare.com/introducing-0-rtt/#whatsthecatch)。或者,为了防止仅
发送第一个握手数据包然后停止应答的反射攻击或DDoS攻击(在TCP中称为

SYN洪水 (↦ https://en.wikipedia.org/wiki/SYN_flood)),QUIC包含重试功能 (↦
https://www.rfc-editor.org/rfc/rfc9000.html#name-address-validation-using-re)。这允许服务器验
证它是否是一个行为良好的客户端,而不必同时保持任何状态(相当于TCP SYN
Cookie (↦ https://en.wikipedia.org/wiki/SYN_cookies))。当然,此重试过程最好发生在后
端服务器之前的某个位置,例如,在负载平衡器上。同样,这需要额外的配置
和通信 (↦ https://tools.ietf.org/html/draft-ietf-quic-load-balancers-06#section-7)来设置。
这些只是网络和系统管理员在使用QUIC和HTTP / 3时遇到的最突出的问题。还
有几个,其中一些我已经谈到过 (↦ https://youtu.be/pq_xk_Pecu4?t=981)。QUIC RFC 还
有两个单独的 (↦ https://datatracker.ietf.org/doc/html/draft-ietf-quic-applicability)随附文档 (↦
https://datatracker.ietf.org/doc/html/draft-ietf-quic-manageability),用于讨论这些问题及其可
能的(部分)缓解措施。

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

HTTP/3和QUIC是复杂的协议,依赖于大量的内部机制。并非所有这一切都已经
准备好进入黄金时段,尽管您已经有一些选择可以在后端部署新协议。但是,
最突出的服务器和底层库(如OpenSSL)可能需要几个月甚至几年的时间才能更
新。

即使这样,正确配置服务器和其他网络中介,以便协议可以以安全和最佳的方
式使用,在更大规模的设置中也将是非同小可的。您需要一个好的开发和运营
团队来正确实现此过渡。

因此,特别是在早期,最好依靠大型托管公司或CDN为您设置和配置协议。如
第 2 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-improvements-
part2/#packet-loss-resilience)所述,这是 QUIC 最有可能获得回报的地方,使用 CDN
是您可以执行的关键性能优化之一。我个人建议使用Cloudflare或Fastly,因为
他们已经密切参与了标准化过程,并将拥有最先进和经过良好调整的实现。

客户端和 QUIC 发现# (↦ #Clients-And-Quic-Discovery)


到目前为止,我们已经考虑了对新协议的服务器端和网络内支持。但是,客户
方面也需要克服几个问题。

在开始之前,让我们从一些好消息开始:大多数流行的浏览器已经具有(实验
性的)HTTP / 3支持!具体而言,在撰写本文时,以下是支持状态(另请参阅

caniuse.com (↦ https://caniuse.com/http3)):
(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/9d4aedbb-8464-
4062-93d4-986989202121/caniuse-h3.png)

浏览器对HTTP / 3的支持已经相当成熟。(资料来源:caniuse.com (↦
https://caniuse.com/http3))(大预览 (↦ https://cloud.netlifyusercontent.com/assets/344dbf88-
fdf9-42bb-adb4-46f01eedd629/9d4aedbb-8464-4062-93d4-986989202121/caniuse-h3.png))

谷歌浏览器(版本91+):默认启用。

Mozilla Firefox(版本 89+):默认启用。

Microsoft Edge(版本 90+):默认启用(内部使用 Chromium)。

Opera(版本 77+):默认启用(内部使用 Chromium)。

Apple Safari(版本 14):在手动标志后面。默认情况下,将在版本 15 中


启用,该版本当前处于技术预览状态。

其他浏览器:我还没有知道的信号(尽管其他内部使用Chromium的浏览
器,如Brave,理论上也可以开始启用它)。

请注意一些细微差别:

大多数浏览器正在逐步推出,因此并非所有用户从一开始就默认启用
HTTP / 3支持。这样做是为了限制单个被忽略的 Bug 可能影响许多用户或
服务器部署过载的风险。因此,即使在最近的浏览器版本中,您也有很小
的几率默认不会获得HTTP / 3,并且必须手动启用它 (↦
https://caniuse.com/http3)。

与服务器一样,HTTP/3 支持并不意味着此时已实现或正在使用所有功能。
特别是,0-RTT、连接迁移、服务器推送、动态 QPACK 标头压缩和 HTTP/3

优先级可能仍然丢失、禁用、谨慎使用或配置不当。

如果要在浏览器外部(例如,在本机应用中)使用客户端 HTTP/3,则必须
集成上面列出的 (↦ https://www.smashingmagazine.com/2021/09/http3-practical-
集成上面列出的 ( https://www.smashingmagazine.com/2021/09/http3 practical
deployment-options-part3/#servers-and-networks)库之一或使用 cURL (↦
https://github.com/curl/curl/blob/master/docs/HTTP3.md)。苹果将很快将原生HTTP / 3
和QUIC支持引入其在macOS和iOS上的内置网络库 (↦
https://developer.apple.com/videos/play/wwdc2021/10094/),微软正在将QUIC添加到
Windows内核及其.NET环境中 (↦ https://docs.microsoft.com/en-
us/aspnet/core/fundamentals/servers/kestrel/http3?view=aspnetcore-6.0),但据我所知,类
似的原生支持尚未宣布用于Android等其他系统。

ALT-SVC# (↦ #ALT-SVC)

即使您已经设置了一个与HTTP / 3兼容的服务器并且正在使用更新的浏览器,您
也可能会惊讶地发现HTTP / 3实际上并没有被一致地使用。为了理解原因,让
我们假设你是浏览器一会儿。您的用户已请求您导航到(您以前从未访问过的
网站),并且您已使用 DNS 将其解析为 IP。将一个或多个 QUIC 握手数据包发
送到该 IP。现在有几件事可能会出错: example.com

01 服务器可能不支持 QUIC。

02 其中一个中间网络或防火墙可能会完全阻止 QUIC 和/或 UDP。

03 握手数据包可能会在传输过程中丢失。

但是,您如何知道(哪个)发生了这些问题之一?在所有这三种情况下,您永
远不会收到对握手数据包的回复。您唯一能做的就是等待,希望回复可能仍然
会进来。然后,经过一段时间的等待(超时),您可能会认为HTTP / 3确实存在
问题。此时,您将尝试打开与服务器的 TCP 连接,希望 HTTP/2 或 HTTP/1.1 能够
正常工作。

如您所见,这种类型的方法可能会引入重大延迟,尤其是在许多服务器和网络
尚不支持QUIC的最初年份。一个简单但幼稚的解决方案是同时打开QUIC和
TCP连接,然后使用首先完成的握手。这种方法被称为“连接赛车”或“快乐的眼
球 (↦ https://en.wikipedia.org/wiki/Happy_Eyeballs)”。虽然这当然是可能的,但它确实有
相当大的开销。即使失去的连接几乎立即关闭,它仍然占用客户端和服务器上

的一些内存和CPU时间(特别是在使用TLS时)。最重要的是,这种方法还存在
其他问题,涉及IPv4与IPv6网络以及前面讨论的重放攻击 (↦
https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/#0-rtt-
connection-set-up)(我的演讲 (↦ https://youtu.be/pq_xk_Pecu4?t=1545)将更详细地介绍)。
因此,对于QUIC和HTTP / 3,浏览器宁愿安全地使用它,并且只有在知道服务
器支持它时才尝试QUIC。因此,第一次联系新服务器时,浏览器将仅通过 TCP
连接使用 HTTP/2 或 HTTP/1.1。然后,服务器可以让浏览器知道它还支持
HTTP/3 进行后续连接。这是通过在通过 HTTP/2 或 HTTP/1.1 发回的响应上设置
一个特殊的 HTTP 标头来完成的。此标头称为 ,代表“替代服务 (↦
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc)”。 可用于让浏览器知道某
个服务也可以通过另一个服务器(IP和/或端口)访问,但它也允许指示替代协
议。这可以在下面的图1中看到。 Alt-Svc Alt-Svc

(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/90f995f5-6b02-
4884-a602-f5a526fb40e2/facebook-alt-svc.png)

图 1:Facebook 包含一个标头,通知浏览器也可以通过 UDP 端口 443 上的


HTTP/3 访问它(有效期为 3600 秒)。目前,协议名称仍然是h3-29或h3-27
(HTTP / 3的第29和第27个草案版本),但这最终将变成h3(一些服务器,
如,今天已经在使用h3)。(大预览 (↦
https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/90f995f5-6b02-
4884-a602-f5a526fb40e2/facebook-alt-svc.png) Alt-Svc google.com )

收到指示 HTTP/3 支持的有效标头后,浏览器将缓存此标头,并尝试从那时起设


置 QUIC 连接。一些客户端将尽快执行此操作(即使在初始页面加载期间 - 见下
文),而其他客户端将等到现有的TCP连接关闭。这意味着浏览器只有在首先

通过HTTP / 2或HTTP / 1.1下载了至少一些资源后才会使用HTTP / 3。即便如


此,它也不是一帆风顺的。浏览器现在知道服务器支持HTTP / 3,但这并不意味
着中间网络不会阻止它。因此,在实践中仍然需要连接赛车。因此,如果网络
以某种方式延迟了QUIC握手,您可能仍然会得到HTTP / 2。此外,如果 QUIC 连
接连续几次无法建立,某些浏览器会将缓存条目放在拒绝列表中一段时间,暂
接连续几次无法建立,某些浏览器会将缓存条目放在拒绝列表中 段时间,暂
时不尝试 HTTP/3。因此,如果出现问题,手动清除浏览器的缓存会很有帮助,
因为这也应该清空绑定。最后,已被证明会带来一些严重的安全风险 (↦
https://www.usenix.org/system/files/woot19-paper_tiwari.pdf)。出于这个原因,一些浏览器对
可以使用哪些端口施加了额外的限制(在Chrome中,您的HTTP / 2和HTTP / 3服
务器需要同时位于低于1024的端口上,或者同时位于高于或等于1024的端口上,
否则将被忽略)。所有这些逻辑在浏览器之间变化和变化很大,这意味着获得
一致的HTTP / 3连接可能很困难,这也使得测试新设置具有挑战性。 Alt-Svc
Alt-Svc Alt-Svc Alt-Svc Alt-Svc

目前正在进行一些工作,以在某种程度上改进这一两步过程。这个
想法是使用称为SVCB和HTTPS (↦ https://datatracker.ietf.org/doc/html/draft-
ietf-dnsop-svcb-https)的新DNS记录,它们将包含类似于 中的信息。因
此,客户端可以在 DNS 解析步骤中 (↦
https://docs.google.com/document/d/1k461sRbddjDGj7Q8f-ZKHZvmB-
ENUWSdX_3Fpp2dmXQ)发现服务器支持 HTTP/3,这意味着它可以从第
一个页面加载开始尝试 QUIC,而不必首先通过 HTTP/2 或 HTTP/1.1。
有关此内容和 的更多信息,请参阅去年关于 HTTP/2 的 Web Almanac
章节 (↦ https://almanac.httparchive.org/en/2020/http2#deploying-and-discovering-
http3)。 Alt-Svc Alt-Svc Alt-Svc

如您所见,HTTP/3 发现过程为本已充满挑战的 QUIC 服务器部署增加了一层复


杂性,因为: Alt-Svc

您将始终需要将HTTP / 3服务器部署在HTTP / 2和/或HTTP / 1.1服务器旁边;

您需要配置 HTTP/2 和 HTTP/1.1 服务器,以在其响应上设置正确的标头。


Alt-Svc

虽然这在生产级设置中应该是可管理的(因为,例如,单个Apache或NGINX实
例可能会同时支持所有三个HTTP版本),但在(本地)测试设置中可能会更烦
人(我已经可以看到自己忘记添加标头或搞砸它们)。由于(当前)缺乏浏览

器错误日志和DevTools指标,这意味着弄清楚为什么设置不起作用可能很困
难。 Alt-Svc

其他问题# (↦ #ADDITIONAL-ISSUES)

似乎这还 够 另 个问题将使本地测试更加 难 使您很难将自签名


似乎这还不够,另一个问题将使本地测试更加困难:Chrome使您很难将自签名
TLS证书用于QUIC。这是因为公司经常使用非官方TLS证书来解密员工的TLS流
量 (↦ https://tlseminar.github.io/tls-interception/#how-ssl-tls-interception-works)(以便他们可
以,例如,让他们的防火墙在加密流量内进行扫描)。但是,如果公司开始使
用QUIC执行此操作,我们将再次拥有自定义中间盒实现,这些实现对协议做出
自己的假设。这可能导致他们将来可能破坏协议支持,这正是我们试图通过首
先对QUIC进行如此广泛的加密来防止的!因此,Chrome对此采取了非常固执己
见的立场:如果您没有使用官方的TLS证书(由Chrome信任的证书颁发机构或
根证书签名,例如Let's Encrypt (↦ https://letsencrypt.org/)),那么您就不能使
用QUIC。可悲的是,这还包括自签名证书,这些证书通常用于本地测试设置。

仍然可以通过一些奇怪的 (↦ https://github.com/GoogleChrome/samples/issues/697)命令行标
志(因为通用代码 (↦ https://github.com/marten-seemann/chrome-quic-interop-
runner/blob/master/run.py#L45)还不适用于QUIC),通过使用每个开发人员的证书
(尽管设置这可能很繁琐),或者在开发PC上设置真正的证书(但这很少是大
型团队的选择,因为你必须与每个开发人员共享证书的私钥)来绕过它 (↦
https://centrifugal.github.io/centrifugo/blog/quic_web_transport/#generate-self-signed-tls-
certificates)。最后,虽然您可以安装自定义根证书 (↦
https://www.freecodecamp.org/news/how-to-get-https-working-on-your-local-development-
environment-in-5-minutes-7af615770eec/),但还需要在启动 Chrome 时 (↦
https://www.chromium.org/quic/playing-with-quic)同时传递 和 标志(见下文 (↦
https://www.smashingmagazine.com/2021/09/http3-practical-deployment-options-part3/#tools-and-
testing))。幸运的是,就目前而言,只有Chrome如此严格,希望其开发人员会
随着时间的推移放松他们的方法。 --ignore-certificate-errors
--origin-to-force-quic-on --ignore-certificate-errors-spki-list

如果您在浏览器中的 QUIC 设置时遇到问题,最好先使用 cURL (↦


https://github.com/curl/curl/blob/master/docs/HTTP3.md) 等工具进行验证。cURL具有出色的
HTTP / 3支持(您甚至可以在两个不同的底层库之间进行选择),并且还使观察
缓存逻辑变得更加容易。 Alt-Svc

这一切意味着什么?# (↦ #WHAT-DOES-IT-ALL-MEAN-2)
除了在服务器端设置HTTP / 3和QUIC所涉及的挑战之外,在让浏览器一致地使
用新协议方面也存在困难。这是由于涉及 Alt-Svc HTTP标头的两步发现过程以
及HTTP / 2连接不能简单地“升级”到HTTP / 3的事实,因为后者使用UDP。

然 使 务 支持 客户端 和 站所有者 也需要处理中间


然而,即使服务器支持HTTP / 3,客户端(和网站所有者!)也需要处理中间网
络可能阻止UDP和/或QUIC流量的事实。因此,HTTP/3 永远不会完全取代
HTTP/2。在实践中,对于首次访问者和非许可网络上的访问者来说,保持良好
的HTTP / 2设置仍然是必要的。幸运的是,正如我们所讨论的 (↦
https://www.smashingmagazine.com/2021/09/http3-practical-deployment-options-part3/#servers-and-
networks),HTTP/ 2和HTTP / 3之间不应该有太多的页面级别更改,所以这应该不
是一个令人头疼的问题。

但是,可能成为问题的是测试和验证您是否使用了正确的配置以及协议是否按
预期使用。这在生产中是正确的,但在本地设置中尤其如此。因此,我预计大
多数人将继续运行HTTP / 2(甚至HTTP / 1.1)开发服务器,仅在以后的部署
阶段切换到HTTP / 3。然而,即便如此,使用当前一代工具验证协议性能也并非
易事。

工具和测试# (↦ #Tools-And-Testing)
与许多主要服务器的情况一样,最流行的Web性能测试工具的制造商从一开始
就没有跟上HTTP / 3的步伐。因此,截至2021年7月,很少有工具对新协议提供
专门支持,尽管它们在一定程度上支持它。

谷歌灯塔# (↦ #GOOGLE-LIGHTHOUSE)

首先是Google Lighthouse (↦ https://developers.google.com/web/tools/lighthouse)工具套件。


虽然这是一个惊人的Web性能工具,但我一直发现它在协议性能方面有些欠
缺。这主要是因为它在浏览器中以相对不切实际的方式模拟了慢速网络 (↦
https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md)(与Chrome的
DevTools处理此问题的方式相同)。虽然这种方法非常有用,并且通常“足够好
(↦ https://www.debugbear.com/blog/network-throttling-methods)”,可以了解慢速网络的影
响,但测试低级协议差异还不够现实 (↦
https://twitter.com/patmeenan/status/1410676572596678657)。由于浏览器无法直接访问 TCP
堆栈,因此它仍会在正常网络上下载该页面,然后人为地延迟数据到达必要的
浏览器逻辑。这意味着,例如,灯塔只模拟延迟和带宽,而不模拟数据包丢失
(正如我们所看到的 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-
improvements-part2/#congestion-control),这是HTTP / 3可能与HTTP / 2可能不同的一个
主要点)。或者,Lighthouse使用高度先进的模拟模型 (↦
https://github com/GoogleChrome/lighthouse/blob/master/docs/lantern md)来猜测实际的网络影
https://github.com/GoogleChrome/lighthouse/blob/master/docs/lantern.md)来猜测实际的网络影
响,因为例如,Google Chrome有一些复杂的逻辑,如果它检测到网络速度较
慢,它会调整页面加载的几个方面。据我所知 (↦
https://github.com/GoogleChrome/lighthouse/issues/12291),这个模型还没有调整到处理 (↦
https://twitter.com/patrickhulce/status/1412401838498910213)IETF QUIC或HTTP/3。因此,如
果您今天使用Lighthouse的唯一目的是比较HTTP / 2和HTTP / 3性能,那么您可
能会得到错误或过度简化的结果,这可能导致您对HTTP / 3在实践中可以为您的
网站做些什么得出错误的结论。一线希望是,从理论上讲,这在未来可以得到
很大的改进,因为浏览器确实可以完全访问QUIC堆栈,因此Lighthouse可以为
HTTP / 3添加更高级的模拟(包括数据包丢失!)。不过,就目前而言,虽然从
理论上讲,Lighthouse可以通过HTTP / 3加载页面,但我建议不要这样做。

网页测试# (↦ #WEBPAGETEST)

其次,有WebPageTest (↦ https://www.webpagetest.org/)。这个惊人的项目允许您从世
界各地的真实设备通过真实网络加载页面,它还允许您在顶部添加数据包级网
络仿真,包括数据包丢失等方面!因此,WebPageTest在概念上处于用于比较
HTTP / 2和HTTP / 3性能的主要位置。然而,虽然它确实已经可以通过新协议加
载页面,但HTTP / 3尚未正确集成到工具或可视化中。例如,目前没有简单的
方法可以通过QUIC强制页面加载,轻松查看实际使用情况,甚至查看QUIC握手
详细信息。在某些情况下,即使查看响应是使用HTTP / 3还是HTTP / 2也可能具
有挑战性。尽管如此,在四月份,我还是能够使用WebPageTest运行相当多的测
试,并看到HTTP / 3的实际运行,我现在将对此进行介绍。 Alt-Svc facebook.com

首先,我运行了 的默认测试,启用了“重复视图”选项。如上所述 (↦
https://www.smashingmagazine.com/2021/09/http3-practical-deployment-options-part3/#alt-svc),我
希望第一个页面加载使用HTTP / 2,这将包括响应标头。因此,重复视图应从一
开始就使用 HTTP/3。在Firefox版本89 (↦
https://www.webpagetest.org/result/210420_AiDcQS_8c1a37579b3b6d291868d0242abb26a1/)中,这或
多或少是发生的事情。但是,在查看单个响应时,我们看到即使在第一个页面
加载期间,Firefox也会切换到使用HTTP / 3而不是HTTP / 2!如图 2 所示,从
第 20 个资源开始会发生这种情况。这意味着Firefox在看到标头后立即建立新的

QUIC连接,并在成功后切换到该连接。如果您向下滚动到连接视图,它似乎还
显示Firefox甚至打开了两个QUIC连接:一个用于凭据的CORS请求,另一个用于
无CORS请求。这是可以预料到的,因为正如我们上面所讨论的 (↦
https://www.smashingmagazine.com/2021/09/http3-practical-deployment-options-part3/#what-does-it-
all-mean-2),即使对于HTTP / 2和HTTP / 3,浏览器也会由于安全问题而打开多个
all mean 2),即使对于HTTP / 2和HTTP / 3,浏览器也会由于安全问题而打开多个
连接。但是,由于 WebPageTest 在此视图中未提供更多详细信息,因此如果不
手动挖掘数据,则很难进行确认。查看重复视图(第二次访问),它首先直接
对第一个请求使用 HTTP/3,如预期的那样。 facebook.com Alt-Svc Alt-Svc

(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7c3ef819-126d-
4140-98ab-2bdf5344854f/firefox-facebook.png)

图 2:Firefox 在第一个页面加载的中途切换到使用 HTTP/3。(大预览 (↦


https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/7c3ef819-126d-
4140-98ab-2bdf5344854f/firefox-facebook.png))

接下来,对于Chrome (↦
https://www.webpagetest.org/result/210420_AiDcP0_6aeaac212f59298cf834ad30b4ec72e6/),我们看
到第一个页面加载的行为类似,尽管在这里Chrome已经打开了第10个资源,比
Firefox早得多。这里更不清楚的是,它是尽快切换,还是仅在需要新连接时切
换(例如,对于具有不同凭据的请求),因为与Firefox不同,连接视图似乎也

没有显示多个QUIC连接。对于重复视图,我们看到了一些更奇怪的事情。出乎
意料的是,Chrome也开始在那里使用HTTP / 2,仅在几次请求后才切换到
HTTP / 3!我还在其他页面上进行了一些 (↦
https://www.webpagetest.org/result/210420_BiDcXS_d2bca9bd9ddce71dfc7bc0618fe7ed11/) (↦
https://www.webpagetest.org/result/210420_AiDc7G_540eaf6f42de75ba9cdf2785528e36e9) 测试 (↦
https://www.webpagetest.org/result/210420_AiDcBR_84d6accab1a208c4eb801df6ef689e5e),以确认
这确实是一致的行为。这可能是由于以下几件事:这可能只是Chrome的当前政
策,可能是Chrome“比赛”了 (↦ https://www.smashingmagazine.com/2021/09/http3-practical-
deployment-options-part3/#alt-svc)TCP和QUIC连接并且TCP最初获胜,或者可能是由于
某种原因,第一个视图中的缓存未被使用。可悲的是,在这一点上,没有简单
的方法来确定问题到底是什么(以及它是否可以修复)。 Alt-Svc

我在这里注意到的另一个有趣的事情是明显的连接合并行为。如上
所述 (↦ https://www.smashingmagazine.com/2021/09/http3-practical-deployment-
options-part3/#http2),HTTP/2 和 HTTP/3 都可以重用连接,即使它们转
到其他主机名,以防止主机名分片的缺点。但是,如图 3 所示,
WebPageTest 报告,对于此 Facebook 负载,连接合并通过 HTTP/3 用于
和 ,而不是通过 HTTP/2 使用(因为 Chrome 为第二个域打开辅助连
接)。然而,我怀疑这是WebPageTest中的一个错误,因为和解析为
不同的IP,因此无法真正合并。 facebook.com fbcdn.net facebook.com

fbcnd.net

该图还显示,当前的 WebPageTest 可视化效果中缺少一些关键的 QUIC 握手信


息。

(↦ https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/dc343577-ecc6-
4d09-9674-8ce22d290870/chrome-facebook-connection.png)

图3:Chrome似乎通过HTTP / 3而不是HTTP / 2合并Facebook连接。(大预览 (↦


https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/dc343577-ecc6-
4d09-9674-8ce22d290870/chrome-facebook-connection.png))

注意:正如我们所看到的,获得“真正的”HTTP / 3有时可能很困难。幸运的是,
特别是对于Chrome,我们还有其他选项可用于以命令行参数的形式测试QUIC和
HTTP / 3。

在WebPageTest的“Chromium”选项卡的底部,我使用了以下命令行选项:

--enable-quic --quic-version=h3-29 --origin-to-force-quic-

on=www.facebook.com:443,static.xx.fbcdn.net:443

该测试的 (↦
https://www.webpagetest.org/result/210420_AiDcY7_ddae6dc06c438d83bb8625cf52951041)结果表
明,这确实从一开始就强制进行QUIC连接,即使在第一个视图中也是如此,从
而绕过了该过程。有趣的是,您会注意到我必须将两个主机名传递给 。当然,
在我没有打开的版本中 (↦
https://www.webpagetest.org/result/210420_BiDcHG_df3438e0dde2f5ea02fc1f865e4e43b8),Chrome
仍然首先打开了与域的HTTP / 2连接,即使在重复视图中也是如此。因此,您需
要手动指示所有QUIC来源才能使其正常工作! Alt-Svc --origin-to-force-quic-on

fbcnd.net

甚至从这几个例子中,我们可以看到,浏览器在实践中实际使用HTTP / 3的方式
有很多事情。似乎他们甚至在初始页面加载期间切换到新协议,尽快或需要新
连接时放弃HTTP / 2。因此,不仅很难获得完整的HTTP / 3负载,而且很难在支
持两者的设置上获得纯HTTP / 2负载!由于WebPageTest尚未显示太多HTTP / 3
或QUIC元数据,因此弄清楚发生了什么可能具有挑战性,并且您也不能从表面
上信任工具和可视化。

因此,如果您使用WebPageTest,则需要仔细检查结果以确保实际使用了哪些协
议。因此,我认为这意味着现在真正测试HTTP / 3性能还为时过早(特别是将
其与HTTP / 2进行比较还为时过早)。并非所有服务器和客户端都实现了所有协
议功能,这一事实加强了这一信念。由于WebPageTest还没有简单的方法来显示
是否使用了0-RTT等高级方面,因此很难知道您实际测量的内容。对于HTTP / 3
优先级功能 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-improvements-
part2/#packet-loss-resilienceg)尤其如此,该功能尚未在所有浏览器中正确实现,并且
许多服务器也缺乏完全支持。由于优先级可能是推动Web性能的一个主要方面
(↦ https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/),因此在不确保至少
此功能正常工作的情况下将HTTP / 3与HTTP / 2进行比较是不公平的(对于两种

协议!不过,这只是一个方面,因为我的研究表明QUIC实现之间的差异有多大
(↦ https://qlog.edm.uhasselt.be/epiq/files/QUICImplementationDiversity_Marx_final_11jun2020.pdf)。
如果您自己进行任何此类比较(或者如果您阅读了此类比较的文章),请100%
确定您已经检查了实际发生的事情。
最后,还要注意,其他更高级的工具(或数据集,如惊人的HTTP Archive (↦
https://httparchive.org/))通常基于WebPageTest或Lighthouse(或使用类似的方
法),所以我怀疑我在这里的大多数评论将广泛适用于大多数Web性能工具。
即使对于那些在未来几个月内宣布支持HTTP / 3的工具供应商 我也会有点怀
即使对于那些在未来几个月内宣布支持HTTP / 3的工具供应商,我也会有点怀
疑,并会验证他们是否真的做对了。但是,对于某些工具,情况可能更糟。例
如,Google的PageSpeed Insights今年只得到了HTTP / 2支持 (↦
https://developers.google.com/speed/docs/insights/release_notes),所以我不会等待HTTP / 3很
快到来。

WIRESHARK、QLOG 和 QVIS# (↦ #WIRESHARK-QLOG-AND-QVIS)

正如上面的讨论所示,此时仅使用Lighthouse或WebPageTest来分析HTTP / 3行
为可能很棘手。幸运的是,其他较低级别的工具可以帮助解决这个问题。首
先,优秀的Wireshark (↦ https://www.wireshark.org/)工具对QUIC有先进的支持,它也
可以通过实验来剖析HTTP/3。这使您可以观察哪些 QUIC 和 HTTP/3 数据包实际
上正在通过网络传输。但是,为了使其正常工作,您需要获取给定连接的TLS解
密密钥,大多数实现(包括Chrome和Firefox)都允许您使用环境变量 (↦
https://www.steffr.ch/inspect-ssl-tls-traffic-from-chrome-firefox-curl-with-wireshark-no-mitm/)提取这
些密钥。虽然这对某些事情很有用,但真正弄清楚发生了什么,特别是对于更
长的连接,可能需要大量的手动工作。您还需要对协议的内部工作原理有非常
深入的了解。 SSLKEYLOGFILE

幸运的是,还有第二个选项,qlog和qvis。qlog (↦ https://github.com/quicwg/qlog) 是一
种基于 JSON 的日志记录格式,专门用于 QUIC 和 HTTP/3,大多数 QUIC 实现都
支持这种格式。qlog不是查看通过线路传输的数据包,而是直接在客户端和服务
器上捕获此信息,这允许它包含一些其他信息(例如,拥塞控制详细信息)。
通常,您可以在使用环境变量启动服务器和客户端时触发 qlog 输出。(请注
意,在 Firefox 中,您需要设置 network.http.http3.enable_qlog (↦
https://bugzilla.mozilla.org/show_bug.cgi?id=1649495)首选项。苹果设备和Safari使用
QUIC_LOG_DIRECTORY (↦ https://developer.apple.com/videos/play/wwdc2021/10094/)。Chrome 还不
支持 qlog。 QLOGDIR

然后,这些qlog文件可以上传到 qvis.quictools.info (↦ https://qvis.quictools.info) 的qvis


工具套件。在那里,您将获得许多高级交互式可视化,可以更轻松地解释
QUIC和HTTP / 3流量。qvis还支持上传Wireshark数据包捕获(文件),并且对
Chrome的netlog文件 (↦ https://www.chromium.org/for-testers/providing-network-details)具有
实验性支持,因此您也可以分析Chrome的行为。关于qlog和qvis的完整教程超出
了本文的范围,但更多细节可以在教程形式 (↦ https://www.youtube.com/watch?
v=HQ1uIClmzkU),论文 (↦
h // l d h l b/ /fil /D b i QUICWi hQl M fi l j df)形式甚
https://qlog.edm.uhasselt.be/anrw/files/DebuggingQUICWithQlog_Marx_final_21jun2020.pdf)形式甚
至脱口秀形式 (↦ https://cloudflare.tv/event/3OM7upT7p3vpAdzphFdhnx)中找到。你也可以
直接问我关于它们的事情 (↦ https://twitter.com/programmingart),因为我是qlog和qvis
的主要实现者。;) .pcap
但是,我并不幻想这里的大多数读者都应该使用Wireshark或qvis,因为它们都
是非常低级的工具。尽管如此,由于我们目前几乎没有替代方案,我强烈建议
不要在不使用这种类型的工具的情况下广泛测试HTTP / 3性能,以确保您真正
了解网络上发生了什么,以及您所看到的是否真的由协议的内部解释而不是其
他因素。

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

正如我们所看到的,在 QUIC 上设置和使用 HTTP/3 可能是一件复杂的事情,很


多事情都可能出错。可悲的是,没有好的工具或可视化可以在适当的抽象级别
公开必要的细节。这使得大多数开发人员很难评估HTTP / 3此时可以为其网站
带来的潜在好处,甚至无法验证他们的设置是否按预期工作。

仅依赖高级指标是非常危险的,因为这些指标可能会被大量因素所扭曲(例如
不切实际的网络仿真,客户端或服务器上缺乏功能,仅部分使用HTTP / 3等)。
即使一切都做得更好,正如我们在第2部分中 (↦
https://www.smashingmagazine.com/2021/08/http3-performance-improvements-part2/#conclusion)所
看到的,在大多数情况下,HTTP / 2和HTTP / 3之间的差异也可能相对较小,这
使得在没有有针对性的HTTP / 3支持的情况下从高级工具中获取必要的信息变得
更加困难。

因此,我建议将 HTTP/2 与 HTTP/3 性能测量单独保留几个月,而是专注于确


保我们的服务器端设置按预期运行。为此,最简单的方法是将WebPageTest与
Google Chrome的命令行参数结合使用,并回退以查找潜在问题 - 这是目前我能
找到的最一致的设置。

结论和要点# (↦ #Conclusion-And-Takeaways)

亲爱的读者,如果您已经阅读了完整的三部分系列并在这里制作,我向您致
敬!即使您只阅读了几节,我也感谢您对这些新的令人兴奋的协议的兴趣。现
在,我将总结本系列的主要内容,为未来几个月和一年提供一些关键建议,最
后为您提供一些其他资源,以防您想了解更多信息。
总结# (↦ #SUMMARY)

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


part1/),我们讨论了需要 HTTP/3 主要是因为新的底层 QUIC 传输协议。QUIC
是TCP的精神继承者,它集成了所有最佳实践以及TLS 1.3。这主要是因为TCP由
于其在中间盒中的无处不在的部署和集成,已经变得太不灵活而无法发展。
QUIC使用UDP和几乎完全加密意味着我们(希望)只需要在将来更新端点即可
添加新功能,这应该更容易。然而,QUIC也增加了一些有趣的新功能。首先,
QUIC的联合传输和加密握手比TCP + TLS更快,并且可以很好地利用0-RTT功
能。其次,QUIC知道它携带多个独立的字节流,并且可以更智能地处理丢失和
延迟,从而缓解线头阻塞问题。第三,QUIC连接可以通过使用连接ID标记每个
数据包来生存用户移动到不同的网络(称为连接迁移)。最后,QUIC灵活的数
据包结构(采用帧)使其更加高效,但在未来也更加灵活和可扩展。总之,很
明显,QUIC是下一代传输协议,将在未来许多年内使用和扩展。

其次,在第 2 部分中 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-


improvements-part2/),我们对这些新功能进行了一些批判性的审视,尤其是它们对
性能的影响。首先,我们看到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 部分中 (↦ #changes-to-pages-and-resources),我们研究了如何实际使用和


部署 QUIC 和 HTTP/3。首先,我们看到从HTTP / 2中学到的大多数最佳实践和
经验教训应该只延续到HTTP / 3。无需更改捆绑或内联策略,也无需对服务器场
进行合并或分片。服务器推送仍然不是最好的功能,同样可以是一个强大的步
兵枪。其次,我们已经讨论过,现成的Web服务器软件包可能需要一段时间才
能提供完整的HTTP / 3支持(部分原因是TLS库支持问题),尽管早期采用者可
以使用大量开源选项,并且几个主要的CDN具有成熟的产品。第三,很明显,
大多数主流浏览器都有(基本的)HTTP / 3支持,即使默认情况下也启用。但
是,在他们实际使用HTTP / 3及其新功能的方式和时间方面存在重大差异,因此
了解他们的行为可能具有挑战性。第四,我们已经讨论过,由于Lighthouse和
WebPageTest等流行工具缺乏明确的HTTP / 3支持,这使得目前特别难以将HTTP
/ 3性能与HTTP / 2和HTTP / 1.1进行比较。总而言之,HTTP/3和QUIC可能还没
有为黄金时段做好准备,但它们很快就会准备好。 preload

建议# (↦ #RECOMMENDATIONS)

从上面的摘要来看,我似乎在提出反对使用QUIC或HTTP / 3的有力论据。然
而,这与我想说的完全相反。

首先,正如第 2 部分 (↦ https://www.smashingmagazine.com/2021/08/http3-performance-
improvements-part2/#conclusion)末尾所讨论的,即使您的“普通”用户可能不会遇到重
大的性能提升(取决于您的目标市场),但您的很大一部分受众可能会看到令
人印象深刻的改进。0-RTT 可能只保存一次往返行程,但对于某些用户来说,
这仍然意味着几百毫秒。连接迁移可能无法持续保持快速下载,但它肯定会帮
助那些试图在高速列车上获取该PDF的人。电缆上的数据包丢失可能是突发的,
但无线链路可能会从QUIC的线头阻塞删除中受益更多。更重要的是,这些用户
通常是那些通常会遇到产品性能最差的用户,因此受其影响最大。如果你想知
道为什么这很重要,请阅读克里斯·扎卡里亚斯(Chris Zacharias)著名的网络表
演轶事 (↦ https://blog.chriszacharias.com/page-weight-matters)。

其次,随着时间的推移,QUIC和HTTP / 3只会变得更好,更快。版本1专注于

完成基本协议,保留更高级的性能功能供以后使用。因此,我觉得现在开始投
资协议是值得的,以确保您可以在它们可用时使用它们和新功能以达到最佳效
果。考虑到协议的复杂性及其部署方面,最好给自己一些时间来熟悉它们的怪
癖。即使您还不想弄脏自己的手,几家主要的CDN提供商也提供成熟的“翻转开
关”HTTP / 3支持(特别是Cloudflare和Fastly)。如果你使用的是CDN,我很难
找到不尝试的理由(如果你关心性能,你真的应该这样做)。
因此,虽然我不会说尽快开始使用QUIC和HTTP / 3至关重要,但我确实觉得已
经有很多好处 而且它们只会在未来增加

You might also like