1、为什么我们需要 HTTP/3?
我经常遇到的一个问题是,“为什么我们在 HTTP/2 之后这么快就需要 HTTP/3,而前者在2015年才刚被标准化?”这确实很奇怪,直到你认识到我们一开始并不真的需要一个新的 HTTP 版本,而是需要一个升级的传输控制协议(TCP)。
TCP 是向 HTTP 等其他协议提供可靠性和有序性传输等服务的主要协议。这也是我们可以在许多并发用户中继续使用因特网的原因之一,因为它有效地将每个用户的带宽限制在公平范围内。
协议之间的分层思想可以很容易地重用它们的特性。上层协议(比如 HTTP)不需要重新实现复杂的特性(比如加密) ,因为下层协议(比如 TLS)已经为它们做了这些。另一个例子是,互联网上的大多数应用程序都在内部使用 TCP 来确保它们的所有数据都被完整地传输。由于这个原因,TCP 是互联网上最广泛被使用和部署的协议之一。
HTTP/2与 HTTP/3协议栈比较:
几十年来,TCP 一直是互联网的基石,但在二十世纪末,它开始显示出它自己的局限性。计划的替代方案是一个名为 QUIC 的传输层协议,该协议在一些关键方面与 TCP 有很大不同,直接在其上运行 HTTP/2 将非常困难。因此,HTTP/3本身是 HTTP/2的一个相对较小的改编,以使其与新的 QUIC 协议兼容,其中包括人们感兴趣的大多数新特性。
之所以需要 QUIC,是因为 TCP 从互联网早期就存在了,它的构建并没有考虑到最大的效率。例如,TCP 需要一个“握手”来建立一个新的连接。这样做是为了确保客户端和服务器都存在,并且它们愿意和能够交换数据。于是在对连接执行任何其他操作之前,就需要一个完整的网络往返。如果客户机和服务器在地理上相距较远,往返时间 (RTT) 就很可能会超过100毫秒,产生明显的网络延迟。
作为第二个例子,TCP 将它传输的所有数据视为一个单独的“文件”或字节流,即使我们实际上在同一时间使用它传输多个文件(例如,当下载包含多个资源的网页时)。这意味着如果包含单个文件数据的 TCP 数据包丢失,那么所有其他文件也将被延迟,直到这些数据包被恢复。
这被称为行首 (head-of-line, HoL) 阻塞。虽然这些效率低下的问题在使用时是可以控制的(否则,我们就不会使用 TCP 超过30年) ,但是它们确实以一种明显的方式影响了更高级别的协议,比如 HTTP。
随着时间的推移,我们尝试改进和升级 TCP,以改善其中一些问题,甚至引入新的性能特性。例如,TCP Fast Open 通过允许更高层的协议从一开始就发送数据,从而消除了握手的开销。另一种方法称为 MultiPath TCP。这里的想法是,你的手机通常同时具有 Wi-Fi 和蜂窝连接,所以为什么不同时使用它们以获得额外的吞吐量和健壮性呢?
实现这些 TCP 扩展并不十分困难。然而,在互联网规模上实际部署它们是极具挑战性的。由于 TCP 非常流行,几乎每个连接的设备都有自己的协议实现。如果这些实现过于陈旧,缺乏更新,或者存在 bug,那么扩展将不能实际使用。换句话说,所有的实现都需要了解扩展,这样扩展才有用。
如果我们只讨论终端用户设备(比如您的计算机或 Web 服务器) ,这不会有太大的问题,因为这些设备可以相对容易地手动更新。但是,许多其他设备位于客户端和服务器之间,这些设备上也有自己的 TCP 代码(例如防火墙、负载均衡器、路由器、缓存服务器、代理等)。
这些中间设备通常更难更新,所接受的实现方面也更严格。例如,如果设备是防火墙,它可能被配置为阻止所有包含未知拓展的通信。实际上,大量的活跃的中间设备对 TCP 做出了某些假设,这些假设已经不再适用于新的扩展。
因此,要更新足够多设备的 TCP 实现以实际大规模使用功能扩展,可能需要数年甚至十年以上的时间。可以说,升级 TCP 实际上已经变得不太可能了。
因此,很明显,我们需要一个 TCP 的替代协议,而不是直接升级,来解决这些问题。然而,由于 TCP 特性及其各种实现的复杂性,从零开始创建一些新的但更好的东西将是一项艰巨的任务。因此,在2010年代初,政府决定推迟这项工作。
毕竟,不仅 TCP 有问题,HTTP/1.1也有问题。我们选择分开工作,首先“修复”HTTP/1.1,导致现在的 HTTP/2。完成这项工作之后,就可以开始更换 TCP 了,现在是 QUIC。最初,我们希望能够在 QUIC 之上直接运行 HTTP/2,但实际上这会使实现效率太低(主要是由于功能重复)。
于是,HTTP/2在一些关键领域进行了调整,使其与 QUIC 兼容。这个经过调整的版本最终命名为 HTTP/3(而不是 HTTP/2-over-QUIC) ,主要是出于市场原因和清晰度。因此,HTTP/1.1和 HTTP/2之间的差异要比 HTTP/2和 HTTP/3之间的差异大得多。
所以说,我们需要的不是真正的 HTTP/3,而是“TCP/2”,我们在这个过程中“免费”得到了 HTTP/3。HTTP/3的主要特性(更快的连接设置、更少的 HoL 阻塞、连接迁移等等)实际上都来自 QUIC。
2、什么是 QUIC?
你可能想知道为什么这很重要?谁在乎这些特性是在 HTTP/3还是 QUIC 中?我觉得这很重要,因为 QUIC 是一个通用的传输协议,就像 TCP 一样,除了 HTTP 和网页加载之外,它还可以用于许多用例。例如,DNS、 SSH、 SMB、 RTP 等都可以在 QUIC 上运行。因此,让我们更深入地了解一下 QUIC,因为我所读到的关于 HTTP/3的大多数误解都来自它。
您可能听说过 QUIC 运行在另一个协议之上,称为用户数据报协议(UDP)。这是真的,但不是因为许多人声称的(性能)原因。理想情况下,QUIC 应该是一个完全独立的新传输协议,直接运行在上面的中显示的协议栈中的 IP 之上。
然而,这样做会导致我们在尝试发展 TCP 时遇到的同样的问题: 为了识别和接受 QUIC,互联网上的所有设备都必须首先进行更新。幸运的是,我们可以在 Internet 上另一个广泛支持的传输层协议 UDP 之上构建 QUIC。
UDP 可以说是最基本的传输层协议。除了所谓的端口号(例如,HTTP 使用端口80,HTTPS 使用端口443,DNS 使用端口53) ,它实际上没有提供任何其他特性。它不通过握手来建立连接,也不可靠,如果 UDP 数据包丢失,它不会自动重新传输。因此 UDP 的“尽最大努力”策略意味着它的性能尽可能好。不需要等待握手建立连接,也没有 HoL 阻塞。在实践中,UDP 主要用于高速更新的实时流量,因此很少受到数据包丢失的影响,因为丢失的数据很快就过时了(例如实时视频会议和游戏)。对于需要较低延迟的情景,它也很有用,例如 DNS 域名查找。
许多人声称是由于性能原因,HTTP/3才在 UDP 之上构建的。他们说 HTTP/3之所以更快是因为像 UDP 一样,它不会建立连接,也不会等待数据包的重传。这些说法是错误的。如前所述,QUIC 使用 UDP,主要是因为拓展UDP更容易实施,因为它已经被 Internet 上的所有设备所了解和实现。
然后,在 UDP 之上,QUIC 实际上重新实现了几乎所有使 TCP 成为如此强大和流行(但有点慢)的协议的特性。QUIC 是绝对可靠的,使用确认收到机制和重传,以确保丢失的数据包仍然到达。QUIC 仍然建立连接,并且握手非常复杂。
最后,QUIC 还使用所谓的流量控制和拥塞控制机制,这些机制可以防止发送方或接收方超载,但是这也会使 TCP 比原始 UDP 慢。关键是 QUIC 以比 TCP 更智能、更高性能的方式实现了这些特性。它结合了几十年的部署经验和 TCP 的最佳实践以及一些核心的新特性。我们将在本文后面更深入地讨论这些特性。
3、变革
那么,QUIC 到底如何改进 TCP 呢?有什么不同吗?0-RTT 数据、连接迁移、更强的数据包丢失恢复和低速网络的适应能力... 这些新概念我们将在本系列的下一部分中详细讨论。然而,所有这些新事物基本上归结为四个主要变化:
- QUIC 与 TLS 深度集成
- 支持多字节流
- 使用连接 ID
- 使用帧技术
(1)没有 TLS 就没有 QUIC
TLS (传输层安全协议)负责保护和加密通过 Internet 发送的数据。使用 HTTPS 时,明文 HTTP 数据首先由 TLS 加密,然后再由 TCP 传输。
TLS、 TCP 和 QUIC 握手对比:
在互联网的早期,加密流量在处理方面是相当昂贵的。此外,它也不被认为对于所有用例都是必要的。历史上,TLS 一直是一个完全独立的协议,可以选择在 TCP 之上使用。这就是为什么我们要区分 HTTP (不带 TLS)和 HTTPS (带 TLS)。
随着时间的推移,我们对互联网安全的态度当然已经转变为“默认安全”。因此,虽然 HTTP/2理论上可以直接在 TCP 上运行而不需要 TLS (甚至在 RFC 规范中将其定义为明文 HTTP/2) ,但实际上没有(流行的) Web 浏览器支持这种模式。在某种程度上,浏览器厂商有意识地以牺牲性能为代价来换取更多的安全性。
考虑到这种明显的朝持久化 TLS 的演变,QUIC 的设计者决定将这种趋势提升到一个新的水平也就不足为奇了。他们没有简单地为 HTTP/3定义明文模式,而是选择将加密深深植入 QUIC 本身。第一个特定于 Google 的 QUIC 版本为此使用了自定义设置,而标准化的 QUIC 直接使用了现有的 TLS 1.3本身。
为此,它打破了协议栈中协议之间典型的干净分离,正如我们在前面的图像中看到的那样。虽然 TLS 1.3仍然可以在 TCP 之上独立运行,但是 QUIC 封装了 TLS 1.3。换句话说,没有 TLS 就无法使用 QUIC; QUIC (进一步说,HTTP/3)总是完全加密的。此外,QUIC 还加密了几乎所有的数据包头字段; 传输层信息(比如数据包编号,从未为 TCP 加密过)不再能够被 QUIC 中间层读取(甚至一些数据包头标志也被加密了)。
对于所有这些,QUIC 首先或多或少地使用 TLS 1.3握手,就像使用 TCP 建立加密参数一样。然而在这之后,QUIC 接管并加密数据包本身,而使用 TLS-over-TCP,TLS 自己进行加密。这个看起来很小的差异代表了一个基本的概念变化,即在更低的协议层实施默认开启的加密。
这种方法为 QUIC 提供了几个好处:
- 对其用户来说更加安全。没有办法运行明文 QUIC,所以攻击者和窃听者可以监听的选项也更少。
- 连接设置更快。对于 TLS-over-TCP,两种协议都需要各自独立的握手,QUIC 则将传输和加密握手合二为一,节省了往返时间。
- 更容易拓展。因为它是完全加密的,所以网络中的中间盒不能再像使用 TCP 那样观察和解释其内部工作原理。因此,它们也不能再在 QUIC 的新版本中(意外地)中断,因为它们无法更新。如果我们希望在未来向 QUIC 添加新特性,我们只需要更新终端设备,而不是所有的中间设备。
然而,除了这些好处,广泛的加密也有一些潜在的缺点:
- 许多网络公司会犹豫是否允许 QUIC。公司可能希望在他们的防火墙上阻止它,因为检测不需要的流量变得更加困难。ISP 和中间网络可能会阻止它,因为像平均延迟和数据包丢失百分比这样的指标不再容易获得,使得检测和诊断问题变得更加困难。这一切都意味着 QUIC 可能永远不会普及。
- 具有更高的加密开销。使用 TLS 对每个数据包进行加密,而 TLS-over-TCP 可以同时对多个数据包进行加密。这可能会使 QUIC 在高吞吐量场景中变慢。
- 使网络更加集中。我经常遇到这样的抱怨,“ QUIC 是被谷歌推动的,因为它让他们完全访问数据,而不与他人分享。”。我基本上不同意。首先,QUIC 不会隐藏更多(或更少!)来自外部观察者的用户级信息(例如,您正在访问的 URL)比 TLS-over-TCP 的用户级信息(QUIC 保持现状)。其次,当 Google 发起 QUIC 项目时,我们今天讨论的最终协议是由互联网工程任务组(IETF)的一个更广泛的团队设计的。IETF 的 QUIC 在技术上与 Google 的 QUIC 大不相同。尽管如此,IETF 的成员大部分来自谷歌和 Facebook 这样的大公司,以及 Cloudflare 和 Fally 这样的 CDN,这是事实。由于 QUIC 的复杂性,它将主要是那些公司有必要的知识,以正确和性能部署,例如,HTTP/3在实践中。这可能会导致这些公司更加集中,这是一个真正令人担忧的问题。