HTTP/2:背景、性能优势和实现
作为 TCP/IP 或传输层的一部分,互联网协议位于互联网基础设施(或物理网络层)之上。 它是我们所有或大部分互联网通信的基础结构。
我们在此之上使用的更高级别的协议层是应用程序层。 在这个层面上,各种应用程序使用不同的协议来连接和传输信息。 我们有用于发送和接收电子邮件的 SMTP、POP3 和 IMAP,用于聊天的 IRC 和 XMPP,用于远程服务器访问的 SSH,等等。
其中最著名的协议是 HTTP(超文本传输协议),它已成为互联网使用的同义词。 这就是我们每天用来访问网站的方式。 早在 1989 年,它就由 CERN 的 Tim Berners-Lee 设计。1.0 版规范于 1996 年发布(RFC 1945),1.1 版于 1999 年发布。
HTTP 规范由万维网联盟维护,可在 https://www.w3.org/standards/techs/HTTP 找到。
该协议的第一代——版本 1 和 1.1——在 2015 年之前一直主导着网络,当时 HTTP/2 发布并且行业——网络服务器和浏览器供应商——开始采用它。
HTTP/1
HTTP 是一种无状态协议,基于请求-响应结构,这意味着客户端向服务器发出请求,并且这些请求是原子的:任何单个请求都不知道之前的请求。 (这就是我们使用 cookie 的原因——弥合一个用户会话中多个请求之间的差距,例如,能够为登录用户提供经过身份验证的网站版本。)
传输通常由客户端(即用户的浏览器)发起,服务器通常只响应这些请求。
我们可以说 HTTP 的当前状态相当“愚蠢”,或者更好,低级,需要向浏览器和服务器提供大量“帮助”以了解如何有效通信。 这个领域的变化引入起来并不那么简单,因为许多现有网站的功能取决于对任何引入的变化的向后兼容性。 为改进协议所做的任何事情都必须以不会中断互联网的无缝方式进行。
在许多方面,当前模型已经成为这种严格的请求-响应、原子、同步模型的瓶颈,并且进展大多采取黑客的形式,通常由谷歌、Facebook 等行业领导者带头。通常的场景,正在以各种方式进行改进,供访问者请求网页,当他们的浏览器从服务器接收到它时,它会解析 HTML 并找到呈现页面所需的其他资源,如 CSS、图像和 JavaScript。 当它遇到这些资源链接时,它会停止加载其他所有内容,并从服务器请求指定的资源。 在收到此资源之前,它不会移动一毫米。 然后它请求另一个,依此类推。
加载世界上最大的网站所需的请求数量通常有数百个。
这包括大量的等待,以及大量的往返,在此期间我们的访问者只能看到一个白屏或半渲染的网站。 这些都是浪费的时间。 在这些请求周期中,大量可用带宽只是坐在那里未使用。
CDN 可以缓解很多这些问题,但即使它们也不过是 hack。
正如 Mozilla 的 Daniel Stenberg(HTTP/2 标准化工作人员之一)指出的那样,该协议的第一个版本很难充分利用底层传输层 TCP 的能力。 一直致力于优化网站加载速度的用户知道这通常需要一些创造力,说得客气一点。
随着时间的推移,互联网带宽速度急剧增加,但 HTTP/1.1 时代的基础设施并没有充分利用这一点。 它仍然在与 HTTP 流水线等问题作斗争——在同一个 TCP 连接上推送更多资源。 浏览器中的客户端支持一直拖得最久,Firefox 和 Chrome 默认禁用它,或者根本不支持,如 IE、Firefox 版本 54+ 等。这意味着即使是小资源也需要打开一个新的 TCP 连接,以及随之而来的所有膨胀——TCP 握手、DNS 查找、延迟……并且由于队头阻塞,加载一个资源会导致加载所有其他资源。
同步、非流水线连接与流水线连接,显示可能节省加载时间。
Web 开发人员在 HTTP/1 模型下不得不求助于一些优化魔法来优化他们的网站,包括图像精灵、CSS 和 JavaScript 连接、分片(将访问者对资源的请求分布到多个域或子域)等.
改进是应该的,它必须以无缝、向后兼容的方式解决这些问题,以免中断现有网络的工作。
SPDY
2009 年,谷歌宣布了一个项目,该项目将成为新一代协议 SPDY(发音为 speedy)的提案草案,增加对 Chrome 的支持,并在随后几年将其推向其所有网络服务。 然后是 Twitter 和服务器供应商,如 Apache、nginx 和 Node.js,后来是 Facebook、WordPress.com 和大多数 CDN 提供商。
SPDY 引入了多路复用——通过单个 TCP 连接并行发送多个资源。 默认情况下,连接是加密的,数据是压缩的。 首先,SPDY 白皮书中对前 25 个站点进行的初步测试显示速度从 27% 提高到 60% 以上。
在生产中证明自己后,SPDY 版本 3 成为 HTTP/2 初稿的基础,由超文本传输协议工作组 httpbis 于 2015 年制定。
HTTP/2 旨在通过以下方式解决困扰协议第一版的问题——延迟问题:
- 压缩 HTTP 标头,通过单个连接实现服务器推送多路复用请求。
它还旨在解决队头阻塞问题。 它传输的数据是二进制格式,提高了效率,并且默认需要加密(或者至少,这是主要浏览器强加的要求)。
通过HPACK算法进行Header压缩,解决了SPDY中的漏洞,将Web请求大小减半。
服务器推送是旨在解决浪费等待时间的功能之一,它通过在浏览器需要之前向访问者的浏览器提供资源。 这减少了往返时间,这是网站优化的一大瓶颈。
由于所有这些改进,在 imagekit.io 的这个示例页面上可以看到 HTTP/2 给表格带来的加载时间差异。
网站拥有的资源越多,加载时间的节省就越明显。
如何查看网站是否通过 HTTP/2 提供资源
在主流浏览器中,如 Firefox 或 Chrome,我们可以在检查器工具中检查网站对 HTTP/2 协议的支持,方法是打开“网络”选项卡并右键单击资源列表上方的条带。 在这里我们可以启用协议项。
另一种方法是安装一个基于 JavaScript 的小工具,它允许我们通过命令行检查 HTTP/2 支持(假设我们安装了 Node.js 和 npm):
npm install -g is-HTTP2-cli
安装后,我们应该可以像这样使用它:
is-HTTP2 www.google.com
✓ HTTP/2 supported by www.google.com
Supported protocols: grpc-exp h2 HTTP/1.1
实现
在撰写本文时,所有主要浏览器都支持 HTTP/2,尽管要求对所有 HTTP/2 请求进行加密,而 HTTP/2 规范本身并不要求加密。
服务器
Apache 2.4 通过其 mod_HTTP2 模块支持它,该模块现在应该可以投入生产了。 Apache 需要通过添加它来构建 --enable-HTTP2
的论点 ./configure
命令。 我们还需要确保至少有 1.2.1 版的 libngHTTP2
安装库。 在系统找不到它的情况下,我们可以提供路径 ./configure
通过增加 --with-ngHTTP2=<path>
.
下一步是通过将指令添加到 Apache 的配置来加载模块:
LoadModule HTTP2_module modules/mod_HTTP2.so
然后,我们将添加 Protocols h2 h2c HTTP/1.1
到我们的虚拟主机块并重新加载服务器。 Apache 的文档警告我们启用 HTTP/2 时的注意事项:
在 Apache 服务器上启用 HTTP/2 会影响资源消耗,如果您的网站很忙,您可能需要仔细考虑其影响。
启用 HTTP/2 后第一件值得注意的事情是您的服务器进程将启动额外的线程。 这样做的原因是 HTTP/2 将它收到的所有请求交给它自己的工作线程进行处理,收集结果并将它们流式传输到客户端。
您可以在此处阅读有关 Apache 配置的更多信息。
nginx 从 1.9.5 版本开始就支持 HTTP/2,我们只需在虚拟主机规范中添加 http2 参数即可启用它:
server {
listen 443 ssl http2 default_server;
ssl_certificate server.crt;
ssl_certificate_key server.key;
然后重新加载nginx。
不幸的是,在撰写本文时,服务器推送尚未正式实施,但已添加到开发路线图中,计划于明年发布。 对于更有冒险精神的人,有一个非官方的 nginx 模块,它添加了对 HTTP/2 服务器推送的支持。
LiteSpeed 和 OpenLiteSpeed 还拥有对 HTTP/2 的支持。
在服务器端激活 HTTP/2 之前的一个警告是确保我们有 SSL 支持。 这意味着我们上面提到的所有虚拟主机片段——用于 Apache 和 nginx——需要进入 SSL 版本的虚拟主机块,监听端口 443。一旦我们安装了 Apache 或 nginx,并且我们配置了常规虚拟主机,获取 LetsEncrypt SSL 证书,并将其安装在任何主要的 Linux 发行版上应该只是几行代码的问题。 Certbot 是一个命令行工具,可以自动执行整个过程。
结论
在本文中,我提供了 HTTP/2 的概览,这是第二代 Web 协议的新的和不断发展的规范。
可以在此处找到新一代 HTTP 实现的完整列表。
对于不太懂技术的人来说,过渡到这个新协议的最短途径可能是简单地将 CDN 实现到 Web 堆栈中,因为 CDN 是 HTTP/2 的最早采用者之一。