findxc/blog

测试对比了一下 HTTP/1.1 和 HTTP/2 的速度

Opened this issue · 2 comments

HTTP/1.1 为什么要限制同一时刻 TCP 连接数量

在 Chrome 中 HTTP/1.1 对于同一个 origin ,同一时刻最多只能有 6 个 TCP 连接。

比如你页面同时找某个源请求 10 个不同资源,那么会有 4 个请求需要排队,如下图所示,末尾的 4 个请求 Waterfall 中有一段灰色的,就表示在排队。

4BCEB76F-A05C-44DD-B28F-398020536293

46ABC7AE-40F6-47B0-8643-D6A0CFC5BDDA

我们可以把请求按 Connection ID 排序,然后在 overview 中选择一个请求结束另一个请求开始的时间段,可以很明显发现同一个 Connection ID 需要等一个请求结束后才会发起下一个请求。

12D59A9A-C667-4AFA-A0A9-33ED142E3D29

如果 Network 中没有 overview 部分,如下所示勾选即可。

7CF1804F-524B-4EDF-B295-8B0118A1B892

那,HTTP/1.1 为什么要做这么一个限制呢?在 HTTP/1.1 - 8.1.4 Practical Considerations 规范中有解释。

Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. These guidelines are intended to improve HTTP response times and avoid congestion.

使用持久连接的客户端需要限制它和某个服务端之间的连接数量。一个客户端和服务端或者代理之间的持久连接数量不应该超过 2 。这个守则是为了优化 HTTP 响应时间和避免拥塞。

规范说的最多只能 2 个连接,然后 Chrome 实际实现是 6 。

比如当访问某个页面的时候,需要向同一个源请求 20 个资源,如果浏览器允许全部一起的话,那就要建立 20 个 TCP 连接,再考虑多个客户端同时请求的场景,那服务端的 TCP 连接就更多了。

所以如果限制了一个客户端同时请求的数量,会一定程度有有助于减轻服务端压力和网络拥塞。

那用了 HTTP/2 就会更快吗

HTTP/2 将一个 TCP 连接分为若干个流(Stream),每个流中可以传输若干消息(Message),每个消息由若干最小的二进制帧(Frame)组成。

客户端和服务器可以将 HTTP 消息分解为互不依赖的帧,然后交错发送,最后再在另一端把它们重新组装起来。

从实际表现上来说,就是当你同时请求 10 个资源时,这 10 个请求会同时发出,并且是在一个 TCP 连接中。如下图所示。

A4B1DEAF-6787-4484-82AE-4112260CD3B8

绿色部分是 TTFB ,Time to First Byte ,请求发出后到接收到响应的第一个字节的时间。

如果我们把 overview 筛选一下只看最后的时间段,我们会发现几乎就是一个请求结束后就会开始下一个请求的蓝色部分。

37EE58E1-6561-4F70-9868-ED0803A47734

蓝色部分是 Content Download ,接收响应的 body 的时间。

暂停一下,先来看个 HTTP/1.1 和 HTTP/2 对比的例子

自己去感受一下 --> HTTP/2: the Future of the Internet | Akamai

DB7C60CC-A91B-45C1-988C-9A88E5A3883C

从这个网站来看,HTTP/2 比 HTTP/1.1 还是快了很多的。

但是,我把同样的例子在我本地试了,速度差异不明显。

1A05ED08-28B0-4CFD-8A36-876764816918

E7E184E5-5EC0-438C-A3FA-9042D5F369DC

为什么会这样呢?或者换个问题,当怎么怎么的时候,才能感受到 HTTP/2 速度上的提升呢?

再回顾一下之前 HTTP/1.1 和 HTTP/2 的图。

047D3CD2-D79D-43DB-A340-4C95397971FE

在 HTTP/1.1 中,对于同一个 TCP 连接,当一个请求结束后,才会开始下一个请求,下一个请求又会经历 TTFB ,然后才会 Content Download 。

这里的 TTFB 就很关键了,它和网络延时以及服务端自身的响应速度有关。这里我们先不考虑服务端自身响应速度,只说网络延时。

网络延时越大,那客户端发出请求后,等待服务端返回第一个字节的时间也就越长。所以对于需要同时请求很多资源的场景, HTTP/1.1 消耗在这上面的时间其实挺长的,并且这个 TCP 连接在 TTFB 的时候,别的啥也干不了,就傻等着。

而在 HTTP/2 中,对于同一个 TCP 连接,所有的请求会一起发出去,然后一个请求结束后,几乎可以马上开始下一个请求的 Content Download 阶段。它省掉的其实就是 HTTP/1.1 中同一个 TCP 连接中除了第一个请求以外其它请求的 TTFB 。

而刚才我们本地测试,因为本地几乎没有网络延时,所以对比出来 HTTP/1.1 和 HTTP/2 没有明显差异。

加上延时我们再来测试一下

在 Network 面板中可以添加自定义的规则来设置网络延迟和下载速度。

1C277C77-C5A4-46CF-BBE1-97A1EBF1EE72

添加一条规则设置网络延时为 50ms 。

CD8E8C3E-80A9-48FA-9A0E-D2609FF1CCAE

然后我们再看一下 HTTP/1.1 和 HTTP/2 的表现。

2B8BD7FB-EEBD-4407-936B-90ED240F489A

BADA1400-1044-49D9-9DF6-1FCD197098AD

我们再测试一下网络延迟为 100ms 时。

D26C03D5-BC50-40DD-A752-3F3B86EFEDED

B37A4932-2C80-429C-B131-09764AE56919

可以发现网络延迟对 HTTP/1.1 的影响较大,对 HTTP/2 几乎没影响。

就是因为在 HTTP/2 中请求是一次性都发出去了,而 HTTP/1.1 中同一个 TCP 连接一个请求结束后才会发起下一个请求,这中间的 TTFB 造成的差异。

那带宽会有影响吗

下面这样就是模拟的 5M 带宽。

0BD051EB-7070-44E3-B19B-35943A5D4C7B

我就不贴图啦,直接说数据。

  • 5M 带宽:HTTP/1.1 是 1.82s ,HTTP/2 是 1.76s
  • 1M 带宽:HTTP/1.1 是 7.96s ,HTTP/2 是 7.69s

可以发现,带宽对两者影响不大,HTTP/2 会稍微快点,因为 HTTP/2 有头部压缩,传输的体积会小一点。

那如果网络延迟和带宽结合起来呢

  • 5M 带宽 50ms 延迟:HTTP/1.1 是 3.53s ,HTTP/2 是 1.73s
  • 1M 带宽 50ms 延迟:HTTP/1.1 是 8.03s ,HTTP/2 是 7.76s

带宽降低时,两个协议的速度差异变小了,说明带宽较小时,带宽才是影响速度的主要因素。

换而言之,如果你的站点所在的服务器带宽比较小,那么升级到 HTTP/2 后加载速度提升不会那么大。如果带宽是够大的,那么由于一般网络延迟都会有 50ms 甚至更大,然后你的站点会需要请求很多静态资源,这时候升级到 HTTP/2 加载速度会有很明显的提升。

那升级还是不升级呢?升呗,只是加载速度提升大还是小的差异,但是总还是有提升嘛。

PS:文中提到的测试代码见 https://github.com/findxc/http-hello/tree/master/http1-vs-http2

因为以前一直只是简单以为 HTTP/2 支持多个请求一起发了而已,然后还有服务端推送啊啥的,但并没 get 到其实更多是对网络延迟的一个优化,现在再去看 HTTP/2 简介 里面的介绍,才有恍然大悟的感觉。

HTTP/2 的主要目标是通过支持完整的请求与响应复用来减少延迟,通过有效压缩 HTTP 标头字段将协议开销降至最低,同时增加对请求优先级和服务器推送的支持。

同时我也在想,如果说自己对 TCP 有更底层一点的了解,应该也更能 get 到 HTTP/2 对于延迟的这个优化 ... 只能说路漫漫其修远兮 ...

其实目前图片这类的一个域名多个资源同时加载的场景 ,大部分都在cdn上了,源站接入层网关开启了这个就要看企业内对这个事的评估