伯阳的网络笔记(三):HTTP/2

754 阅读6分钟

因为疫情期间在外当志愿者,晚上回家无聊翻翻网络知识,权当记录了。
初始动笔:2019-02-06
修改时间:2019-03-27
GitHub Repo:BoyangBlog

1. HTTP/1.x 的问题

不得不说, HTTP/1.1 是一个伟大的协议,现在仍然有非常多的网站使用它,充分说明了它的健壮、巧妙。但是,它毕竟是一个创建于互联网时代前的协议,虽然已经很有预见性了,但是仍然有些过时了。主要有以下几个问题:

  1. HTTP 只允许每个 TCP 连接有一个未完成的请求,会有队首阻塞的问题;
  2. 对于同一个域名,浏览器最多可以同时创建 6~8 个 TCP 连接;
  3. Header 有点过大了;
  4. 为了尽可能减少请求数,需要做合并文件、减少图像等优化工作,但是这无疑造成了单个请求内容变大延迟变高的问题;
  5. 明文传输。

所以,随着求变的声音越来越多,HTTP/2 应声而出。

2. SPDY

等一下,正式讲到 HTTP/2 之前,我们需要先提一下 SPDY

因为迟迟没有 HTTP/1.1 的优化出线,谷歌自己推出了一个新的网络协议,叫做 SPDY,它的很多设计,被采用到了 HTTP/2 当中,比如说多路复用、二进制分帧、头部压缩、服务器推送等等。

3. HTTP/2 简介

在2012年,W3C向社会征求 HTTP/2 的建议,然后决定将 SPDY 当做制定标准的基础。目标上, HTTP/2 致力于突破上一代协议众所周知的性能限制,对 HTTP/1.x 进行扩展,而非替代,核心概念不会改变。下图展示了 HTTP/1 和 HTTP/2 的区别。

它做了很多改变,下面细讲。 不过在讲之前,要先解释 HTTP/2 中的几个概念:


  • 已建立的连接上的双向字节流
  • 消息
    与逻辑消息对应的完整的一系列数据帧

  • HTTP/2 通信的最小单位

所有的 HTTP/2 通信都是在一个 TCP 连接上完成,这个连接可以承载任意数量的双向数据流。相应的,每个数据流以消息的形式发送,而消息由一个或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流表示符重新组装。

二进制分帧

HTTP/2 性能增强的核心,全在于新增的二进制分帧层,它定义了如何封装 HTTP 消息并在客户端与服务器之间传输。

这里的”层”,指的是位于会话层和应用层之间的一个新的机制:HTTP 的语义不受影响,不同的是传输期间对它们的编码方式改变了。HTTP/1.x 以换行符作为纯文本的分隔符,而 HTTP/2 将所有传输的信息分割为更小的消息和帧,并对他们采用了二进制格式的编码。

多向请求和响应

在 HTTP/1.x 中,如果客户端想要发送多个并行的请求以改进性能,那么必须使用多个 TCP 连接;每个连接每次只交付一个响应,多个响应必须要排队。更糟糕的在于,这样非常容易发生队首堵塞,从而造成 TCP 连接效率低下。

HTTP/2 中的二进制分帧,突破了这种限制,客户端和服务器可以把 HTTP 消息分解为互不依赖的帧,然后乱序发送,然后在另一端把他们重新组合起来。如下如所示。

将 HTTP 消息分解为独立的帧,交错发送,然后在另外一端重新组装是 HTTP/2 最重要的一项增强。它带来了以下几个优点:

  • 可以并行交错的发送请求,请求之间互不影响;
  • 可以并行交错的发送响应,响应之间互不干扰;
  • 只使用一个连接即可并行发送多个请求和响应(多路复用);
  • 消除不必要的延迟;
  • 不必再继续在为了绕过 HTTP/1.x 的限制做很多工作;
  • ......

总之,这个技术解决了 HTTP/1.1 中存在的队首阻塞问题,也消除了并行处理和发送请求及响应时对多个连接的依赖。

流量控制

在同一个 TCP 上传输多个数据流,就意味着要共享带宽。标定数据流的优先级有助于按序交付,但只有优先级还不足以确定多个数据流或多个连接之间的资源分配。所以,HTTP/2 提供了一个简单的机制:

  • 流量控制基于每一跳进行,而非端到端的控制;
  • 流量控制基于窗口更新帧进行,即接收方广播自己准备接受某个数据流的多少字节,以及对整个连接要接收多少字节;
  • 流量控制窗口大小通过 WINDOW_UPDATE 帧更新;

我们可以发现,它和 TCP 流量控制非常类似,事实上这两个机制是一样的。

这个由程序员手动控制。

服务器推送

服务器可以对一个客户端请求发送多个响应。换句话说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。

因为有些资源,比如去线上阅读说一本书,就可以预测到下一步可能的阅读的页面,进而提前进行缓存。

首部压缩

HTTP 的每一次通信都会带一组完整的首部,用于描述传输的资源及其属性。在 HTTP/1.1 中,这些数据都是以纯文本的形式发送的,通常会给每个请求增加 500~800 字节的负荷;如果再算上 cookie ,增加的负荷可能会加大到上千字节。为了减少这些开销,HTTP/2 会压缩首部数据。

HTTP/2 连接的两端都知道已经发送了哪些首部,这些首部是什么,从而可以针对之前的数据只编码发送差异数据。

4. 加密

虽然一直有加入 TLS 的提议,但是最后 HTTP/2 并未强制加入 TLS。只是有些网站会加上。

5. HTTP/2 和 HTTP/3

HTTP/2 依然是以 TCP 作为基础的,但是 TCP 依然会有三次握手消耗时间,为了优化它,谷歌专门搞了一个基于 UDP 协议的 QUIC 协议。这个协议正在被一些大厂使用,但是因为源于 UDP 协议,有可能被运营商破坏,前景依然需要观察。

QUIC的相关原理可以查看科普:QUIC协议原理分析这篇文章。

总结

总的来说,HTTP/2 是基于 HTTP/1.1 进行的拓展,有效的优化了速度和数据量。在多路复用、二进制分帧、头部压缩、服务器推送上的优化非常的精妙和让人陶醉。

引用

RFC7540:Hypertext Transfer Protocol Version 2 (HTTP/2)

SPDY Wiki

《Web性能权威指南》