(译)HTTP/3 的漫长之路(The Long Road to HTTP/3)

当 HTTP/3 规范还处于草稿状态时,最新版本的 Chrome 浏览器已经默认支持 HTTP/3 了。因为Chrome占据了浏览器70%的市场份额,你能够说 HTTP/3 已经成为主流。html

这个基础协议的新修订旨在使web更加高效、安全,并缩短内容传输的延迟。它大胆地采用了一个新的、专门构建的协议 QUIC 来替换底层 TCP 协议。解释 QUIC 优势的最好方法是说明 TCP 做为 HTTP 请求传输的不足之处。要作到这一点,咱们要从头开始提及。web

原始的 HTTP

1991年,当 Tim Berners-Lee 爵士正式设计了一个简单的单行超文本交换协议时,TCP已是一个古老、可靠的协议。后来被称为 HTTP 0.9 的原始定义文档特别提到 TCP 是一个首选的、但不是惟一的传输协议:算法

注意:HTTP目前运行在 TCP 之上,可是它能够运行在任何面向链接的服务上。( Note: HTTP currently runs over TCP, but could run over any connection-oriented service.

固然了,这个概念验证版的 HTTP 跟如今咱们熟知的 HTTP 已经相差很大。它没有标题,也没有状态码(status code)。典型的请求就像 ​GET /path​ 同样简单。响应只包含 HTML,并在结束时关闭TCP链接。因为浏览器还不存在,用户须要直接阅读 HTML。它能够连接到其余资源,可是早期版本的 HTML 中没有异步地请求其余资源的标签。一个 HTTP 请求就提供了一个完整的、自给自足的页面。chrome

HTTP/1.0 的出现

在随后的几年里,因特网迅速发展,HTTP 逐渐发展成为一种可扩展和灵活的通用协议,尽管传输HTML 仍然是它的主要专长。HTTP的三个关键更新促成了这一演变:浏览器

  • HTTP 方法(methods)的引入容许客户的指明它想要执行的操做类型。例如,建立 POST 是为了容许客户端向服务器发送数据以进行处理和存储。
  • 状态码(status code)为客户端提供了一种方法,用于确认是否服务器已成功处理请求,若是没有,还能够了解发生了什么类型的错误。
  • headers 添加了将结构化文本元数据(metadata)附加到请求和响应的能力,它能够修改客户端或服务端的行为。例如,encodng 和 content-type 类型 headers 容许 HTTP 不只能够传输HTML,还能够传输任何类型的payload。“Compression” header 容许客客户端和服务器协商支持的压缩格式,从而减小链接传输的数据量。

与此同时,HTML 先进到支持图像、样式和其余连接资源。浏览器如今被迫执行多个请求来显示一个单独的网页,而最初的“每一个请求一个链接”体系结构并非为了处理这一问题设计的。创建和结束一个TCP链接须要大量来回的数据包交换,所以在延迟(latency)开销方面相对昂贵。当一个网页由一个单独的文本文件组成时,这并不重要,可是随着每一个页面的请求数量的增长,延迟(latency)也随之增长。缓存

下图说明了每一个请求创建一个新的 TCP 链接所涉及的开销。安全

所以建立了一个 “connection” header来解决这个问题。客户端发送一个带有 “connection: keep-alive” header 的请求,表示为后续的请求保持TCP链接打开。若是服务器理解这个头并赞成接受它,它的响应也将包含 “connection: keep-alive” head。这样,双方都会保持 TCP 通道的打开状态,并将其用于后续通讯,直到任何一方决定关闭它。随着 SSL/TLS 加密的普及,这变得更加剧要,由于协商加密算法和交换加密密钥须要在每一个链接上附加一个额外的请求/响应周期。服务器

当时,许多 HTTP 的改进都是自发出现的。当一个流行的浏览器或服务端应用发现须要一个新的HTTP特性时,他们只需本身实现它,并但愿其余各方也能跟随效仿。讽刺的是,一个去中心化的网络须要一个集权的管理机构来避免 HTTP 分裂成各类不兼容的碎片。Tim Berners-Lee,该协议的最初创造者,认识到了这一危险,并于1994年成立了万维网联盟(W3C),该联盟与互联网工程任务组(IETF)一块儿致力于互联网技术的规范化。做为第一步,他们记录了当时使用 HTTP 中的最多见的特性,并将其命名为HTTP/1.0。然而,因为这个“规范”描述了各类各样的,每每不一致的技术,它历来没有获得一个标准的状态。所以,新版本 HTTP 协议的工做已经开始。网络

HTTP/1.1 的标准化

HTTP/1.1 修复了 HTTP/1.0 的不一致性,并调整了协议,使其在新的 web 生态中更高效。引入的两个最关键的变化是在默认状况下使用持久的 TCP 链接(keep-alive)和 HTTP 管道(pipelining)。异步

HTTP 管道(pipelining)简单地说,客户端不须要等待服务器响应请求以后,才能发送后续的HTTP 请求。这个特性使得带宽的使用更加有效,延迟也减小了,可是它还能够获得更大的改进。HTTP 管道(pipelining)仍然要求服务器按照接收到的请求的顺序进行响应,所以,若是管道中的单个请求执行缓慢,则对客户端的全部后续响应都将相应地延迟。这个问题被称为队头阻塞(head-of-the-line blocking)。

此时此刻,web 正在得到愈来愈多的交互功能。web2.0 就在眼前,一些网页包含几十个甚至几百个外部资源。为了解决队头阻塞(head-of-the-line blocking)的问题,并下降页面加载速度,客户端在每台主机上创建多个TCP链接。固然,链接开销历来是毫无目的。在现实中,因为愈来愈多的应用程序使用了 SSL/TLS 加密 HTTP 通讯,状况变得更糟糕了。所以,大多数浏览器都设置了最大能够同时链接的限制,以达到微妙的平衡。

许多较大的web服务已经认识到,现有的限制对于其异常繁重的交互式web应用程序来讲过于局限,所以它们经过多个域名分发应用程序来“玩弄系统(gamed the system)”。无论怎么说,这一切都奏效了,但解决方案远非优雅之举。

尽管有一些缺点,但 HTTP/1.0 和 HTTP/1.1 的简单性使它们得到了普遍的成功,并且在过去的十年里,没有人认真地尝试改变它们。

SPDY 和 HTTP/2

2008年,谷歌发布了 Chrome 浏览器,该浏览器因其快速和创新而迅速受到欢迎。它给了谷歌在互联网技术问题上的强大投票权。2010年代初期,谷歌在Chrome上增长了对其网络协议SPDY的支持。

HTTP/2 标准是在 SPDY 的基础上进行改进的。HTTP/2 经过在单个打开的TCP链接上多路传输 HTTP 请求,解决了对头阻塞(head-of-the-line blocking)问题。这容许服务器以任何顺序响应请求,而后客户端能够在收到响应时从新组合响应,从而在单个链接中加快整个交换的速度。

事实上,使用 HTTP/2 服务端能够在客户端请求资源以前就将其提供给客户端!举个例子,若是服务端知道客户机极可能须要一个样式来显示一个HTML页面,那么它能够将CSS“推”给客户端,而无需等待相应的请求。虽然在理论上这个功能颇有用,但在实践中不多见到这种特性,由于它须要服务器理解它所服务的HTML的结构,这种状况不多发生。

除了请求正文以外,HTTP/2还容许压缩请求头,这进一步减小了经过网络传输的数据量。

HTTP/2 为web 解决了不少问题,但并非全部的问题。在TCP协议层上,仍然存在相似的对头阻塞( head-of-the-line)问题,TCP协议仍然是 web 的基本组成部分。当一个 TCP 包在传输过程当中丢失时,在服务器从新发送丢失的包以前,接收方没法确认传入的包。因为 TCP 在设计上不受诸如 HTTP 之类的高级协议的影响,所以一个丢失的数据包将阻塞全部正在传输的HTTP请求的流,直到丢失的数据被从新发送。这个问题在不可靠的链接上尤其突出,这在无处不在的移动设备时代并很多见。

HTTP/3 变革

因为 HTTP/2 的问题不能彻底在应用层解决,协议的新迭代必须更新传输层。然而,建立一个新的传输层协议并非一件容易的事情。传输协议须要硬件供应商的支持和大多数网络运营商的部署,这些运营商因为所涉及的成本和影响而不肯更新。以 IPv6 为例:它是24年前引入的,如今还远未获得广泛支持。

幸运的是,还有另外一个选择。UDP 协议和 TCP 同样受到普遍的支持,但它很是简单,能够运行在其上的建立自定义协议。UDP数据包是一次性的:没有握手、持久链接或错误更正。HTTP3 背后的主要思想是放弃TCP,转而使用基于 UDP 的 QUIC 协议。QUIC 以一种对 web 环境有意义的方式添加了必要的特性(那些之前由 TCP 提供的特性等等)。

跟 HTTP2 不同,HTTP2 容许未加密链接,QUIC 严格要求经过加密建立链接。此外,链接中的全部数据也应用了加密,而不只仅是 HTTP payload,它能够防止全部类型的安全问题。在QUIC中,创建持久链接、协商加密协议、甚至发送第一批数据都被合并到一个请求/响应周期中,从而大大下降了链接延迟。若是客户端在本地缓存了加密参数,则能够经过简化的握手(0-RTT)从新创建与已知主机的链接。

为了解决传输级别的队头阻塞(head-of-the-line blocking)问题,经过QUIC链接传输的数据被分红流(streams)。在持久的QUIC链接中,流(streams)是的短生命(short-lived)、独立的“子链接”。每一个流(streams)处理本身的纠错和传递保证,但使用全局链接的压缩和加密属性。每一个客户端发起的 HTTP 请求都在一个单独的流(streams)上运行,所以丢失一个包不会影响其余流/请求的数据传输。

UDP是一种无状态协议(持久链接只是其之上的一种抽象),这使得 QUIC 可以在很大程度上忽略包传递的复杂性。例如,客户端更改其 IP 地址(例如智能手机从移动网络跳到家庭wifi)理论上不该该中断链接,由于该协议容许在不一样IP地址之间迁移而无需从新链接。

现有QUIC协议的全部实现都在用户态(userspace)而不是操做系统内核中运行。因为客户端(例如浏览器)和服务端的更新一般比操做系统内核更新得更频繁,这将有望加快新功能的采用。


HTTP/3 的问题

在我看来,虽然 HTTP/3 标准是朝着更快、更安全的互联网迈进的一大步,但它并不完美。它的一些问题是由其新颖性引发的,而另外一些问题彷佛是协议固有的。

TCP 协议已经存在了好久了,路由器很容易理解它。它有明确的未加密标记,用于创建和关闭链接,可用于跟踪和控制现有会话。在网络硬件学会理解新协议以前,它将把 QUIC 通讯简单地看做一个独立的UDP包流,这将使网络配置更加复杂。

从客户端缓存“恢复”(revive)链接的能力,使得协议对重放攻击(replay attack)开放了:在某些状况下,恶意攻击者能够从新发送先前捕获的数据包,这些将被服务器解释为来自受害者有效的数据包。许多web服务器,像那些提供静态内容的服务器,不会受到这种攻击的损害。对此攻击场景有效的应用程序必须记住禁用 0-RTT 功能。

这就是目前为止 HTTP 的故事。我认为HTTP/3是向前迈进的一大步,固然但愿 HTTP/3 在不久的未来获得普遍采用。

相关文章
相关标签/搜索