Intro to HTTP/2

简介
HTTP/2 主要目的是提高网页性能,最近几年比较火,将其单独抽成一块讲。2015 年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。
目前还有不少服务还是 HTTP/1.1,NodeJS 也是从 v10 才将 http2 转正。Express5.x 才开始支持 http/2。

可以打开谷歌首页看看,基本上都是 http/2 协议,简写成 h2

HTTPS 是 HTTP/2 的必要条件。
可以用 Chrome 插件可以用来检测 HTTP/2:HTTP/2 and SPDY indicator。它会给浏览器添加了一个闪电标记:

- 蓝色闪电,表示这个网页是运行在 HTTP/2 上
- 红色闪电表示网页运行在 SPDY 上(spdy 和 h2 的关系和参考这篇文章:HTTP 协议入门)
- 灰色闪电则表示着这个网页既不是运行于 HTTP/2,也不是运行于 SPDY
一个 TCP 连接

图:HTTP/1.1与HTTP/2数据传输对比图
由上图可以看出,HTTP/1.1 中同一个 TCP 连接里面,上一个响应发送完了,服务器才能发送下一个。而 HTTP/2 采用多路复用(后面介绍)允许单一的 TCP 连接同时发起多重的请求响应,比如 GET style.css
和 GET script.js
差不多就是同时发送的。
Chrome 在 HTTP/1.1 中会建立 6 个 TCP ,在 HTTP/2 中同域名下会建立 1 个 TCP 。
二进制传输
HTTP/1.1 头信息是文本(ASCII 编码),数据体可以是文本,也可以是二进制。这样就会引发一个问题:所有的数据必须按顺序传输,比如需要传输:helloworld
,只能从 h 到 d 一个一个的传输,不能并行传输,因为接收端并不知道这些字符的顺序,所以并行传输在 HTTP/1.1 是不能实现的。

HTTP/2 则是一个彻底的二进制协议,二进制协议解析起来更高效。头信息和数据体都是二进制,并且统称为"帧"(frame):
- 头信息帧(HEADERS frame):存放头数据
- 数据帧(DATA frame):存放实体数据

它把 TCP 协议的部分特性挪到了应用层,把原来的 "Header+Body" 的消息"打散"为数个小 片的二进制帧,HTTP/2 数据分帧后 "Header+Body" 的报文结构就完全消失了,协议看到的只是一个个的"碎片"。这样发送的时候先后顺序无所谓了,可以根据帧号将它们重新排列起来。这样同一个 TCP 连接里面同时发生多个请求响应。


帧对数据进行顺序标识,如下图所示,这样浏览器收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况。同样是因为有了序列,服务器就可以并行的传输数据,这就是流所做的事情。

二进制的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多,且解析起来更高效。。
多路复用(Multiplexing)
解决两大问题
在 HTTP/2 中引入了多路复用的技术,解决了 keep-alive 的性能问题。主要包括:
(1) 内存占用更少,连接吞吐量更大
浏览器限制同一个域名下的请求数量。HTTP/2 对同一域名下所有请求都是基于流,也就是说同一域名不管访问多少文件,也只建立一个 TCP 连接。同样 Apache 的最大连接数为 300,因为有了这个新特性,最大的并发就可以提升到 300,比原来提升了 6 倍。
(2) 提高传输的速度,降低延迟
新开一个 TCP 连接都需要慢慢提升传输速度。HTTP 性能优化的关键并不在于高带宽,而是低延迟。TCP 连接会随着时间进行自我调谐,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐则被称为 TCP 慢启动。由于这种原因,让原本就具有突发性和短时性的 HTTP 连接变的十分低效。
HTTP/2 通过让所有数据流共用同一个连接,可以更有效地使用 TCP 连接,让高带宽也能真正的服务于 HTTP 的性能提升。
实例对比
大家可以通过该在线 Demo 直观感受下 HTTP/2 比 HTTP/1 到底快了多少。

下图是请求的对比:


第二张图中,感觉有很多个 TCP 连接,但是放大看就会发现它们都是一个 TCP 连接,只是发送请求的时间间隔非常短。
主要特性
在 HTTP/2 中,有了二进制分帧之后,HTTP/2 不再依赖 TCP 连接去实现多流并行了,在 HTTP/2 中:
- 同域名下所有通信都在单个连接上完成。
- 单个连接可以承载任意数量的双向数据流。
- 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
这一特性,使性能有了极大提升:
- 同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应,这样整个页面资源的下载过程只需要一次慢启动,同时也避免了多个 TCP 连接竞争带宽所带来的问题。
- 并行交错地发送多个请求/响应,请求/响应之间互不影响。
- 在 HTTP/2 中,每个请求都可以带一个 31bit 的优先值,0 表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。

如上图所示,多路复用的技术可以只通过一个 TCP 连接就可以传输所有的请求数据。