写点什么

HTTP/2 做错了什么?刚刚辉煌 2 年就要被弃用了

发布于: 2021 年 04 月 28 日
HTTP/2做错了什么?刚刚辉煌2年就要被弃用了

最近一段时间以来,关于 HTTP/3 的新闻有很多,越来越多的国际大公司已经开始使用 HTTP/3 了。



所以,HTTP/3 已经是箭在弦上了,全面使用只是个时间问题,那么,作为一线开发者,我们也是时候了解下到底什么是 HTTP/3,为什么需要 HTTP/3 了。

于是,我准备开始写这篇文章,但是要想把 HTTP/3 的事情说清楚,一定绕不过的问题就是 HTTP/2,所以写着写着,篇幅越来越多,于是我就把他们分成了上下两篇。

这一篇我们主要来回顾下 HTTP/2,然后再来重点看一下 HTTP/2 存在哪些问题,为什么要被弃用。

HTTP/2 辉煌不在?

虽然 HTTP/2 标准在 2015 年 5 月就以 RFC 7540 正式发表了,并且多数浏览器在 2015 年底就支持了。

但是,真正被广泛使用起来要到 2018 年左右,但是也是在 2018 年,11 月 IETF 给出了官方批准,认可 HTTP-over-QUIC 成为 HTTP/3。

2018 年的时候,我写过一篇文章介绍《HTTP/2 到底是什么?》,那时候 HTTP/2 还是个新技术,刚刚开始有软件支持,短短两年过去了,现在 HTTP/3 已经悄然而至了。

**根据 W3Techs 的数据,截至 2019 年 6 月,全球也仅有 36.5%的网站支持了 HTTP/2。**所以,可能很多网站还没开始支持 HTTP/2,HTTP/3 就已经来了。

所以,对于很多网站来说,或许直接升级 HTTP/3 是一个更加正确的选择。

回顾 HTTP/2

在阅读本文之前,强烈建议大家先阅读下《HTTP/2 到底是什么?》这篇文章,这里面介绍了 HTTP 的历史,介绍了各个版本的 HTTP 协议的诞生的背景。

当你读到这里的时候,我默认大家对 HTTP/2 有了一定的基本了解。

我们知道,HTTP/2 的诞生,主要是为了解决 HTTP/1.1 中的效率问题,HTTP/2 中最核心的技术就是多路复用技术,即允许同时通过单一的 HTTP/2.0 连接发起多重的请求-响应消息。


同时还实现了二进制分帧、header 压缩、服务端推送等技术。

从 HTTP/1.0 诞生,一直到 HTTP/2,在这 24 年里,HTTP 协议已经做过了三次升级,但是有一个关键的技术点是不变的,那就是这所有的 HTTP 协议,都是基于 TCP 协议实现的。

流水的 HTTP,铁打的 TCP。这是因为相对于 UDP 协议,TCP 协议更加可靠。

虽然在 HTTP/1.1 的基础上推出 HTTP/2 大大的提升了效率,但是还是有很多人认为这只是个"临时方案",这也是为什么刚刚推出没多久,业内就开始大力投入 HTTP/3 的研发与推广了。

而这背后的深层次原因也正是因为他还是基于 TCP 协议实现的。TCP 协议虽然更加可靠,但是还是存在着一定的问题,接下来具体分析下。

HTTP/2 问题

队头阻塞

队头阻塞翻译自英文 head-of-line blocking,这个词并不新鲜,因为早在 HTTP/1.1 时代,就一直存在着队头阻塞的问题。

但是很多人在一些资料中会看到有论点说 HTTP/2 解决了队头阻塞的问题。但是这句话只对了一半。

只能说 HTTP/2 解决了 HTTP 的队头阻塞问题,但是并没有解决 TCP 队头阻塞问题!

如果大家对于 HTTP 的历史有一定的了解的话,就会知道。HTTP/1.1 相比较于 HTTP/1.0 来说,最主要的改进就是引入了持久连接(keep-alive)。

所谓的持久连接就是:在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。


引入了持久连接之后,在性能方面,HTTP 协议有了明显的提升。

另外,HTTP/1.1 允许在持久连接上使用请求管道,是相对于持久连接的又一性能优化。

所谓请求管道,就是在 HTTP 响应到达之前,可以将多条请求放入队列,当第一条 HTTP 请求通过网络流向服务器时,第二条和第三条请求也可以开始发送了。在高时延网络条件下,这样做可以降低网络的环回时间,提高性能。


但是,对于管道连接还是有一定的限制和要求的,其中一个比较关键的就是服务端必须按照与请求相同的顺序回送 HTTP 响应。

这也就意味着,如果一个响应返回发生了延迟,那么其后续的响应都会被延迟,直到队头的响应送达。这就是所谓的 HTTP 队头阻塞

但是 HTTP 队头阻塞的问题在 HTTP/2 中得到了有效的解决。HTTP/2 废弃了管道化的方式,而是创新性地引入了帧、消息和数据流等概念。客户端和服务器可以把 HTTP 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。


因为没有顺序了,所以就不需要阻塞了,就有效的解决了 HTTP 对队头阻塞的问题。

但是,HTTP/2 仍然会存在 TCP 队头阻塞的问题,那是因为 HTTP/2 其实还是依赖 TCP 协议实现的。

TCP 传输过程中会把数据拆分为一个个按照顺序排列的数据包,这些数据包通过网络传输到了接收端,接收端再按照顺序将这些数据包组合成原始数据,这样就完成了数据传输。

但是如果其中的某一个数据包没有按照顺序到达,接收端会一直保持连接等待数据包返回,这时候就会阻塞后续请求。这就发生了 TCP 队头阻塞

HTTP/1.1 的管道化持久连接也是使得同一个 TCP 链接可以被多个 HTTP 使用,但是 HTTP/1.1 中规定一个域名可以有 6 个 TCP 连接。而 HTTP/2 中,同一个域名只是用一个 TCP 连接。

所以,在 HTTP/2 中,TCP 队头阻塞造成的影响会更大,因为 HTTP/2 的多路复用技术使得多个请求其实是基于同一个 TCP 连接的,那如果某一个请求造成了 TCP 队头阻塞,那么多个请求都会受到影响。

TCP 握手时长

一提到 TCP 协议,大家最先想到的一定是他的三次握手与四次关闭的特性。

因为 TCP 是一种可靠通信协议,而这种可靠就是靠三次握手实现的,通过三次握手,TCP 在传输过程中可以保证接收方收到的数据是完整,有序,无差错的。

但是,问题是三次握手是需要消耗时间的,这里插播一个关于网络延迟的概念。

网络延迟又称为 RTT(Round Trip Time)。他是指一个请求从客户端浏览器发送一个请求数据包到服务器,再从服务器得到响应数据包的这段时间。RTT 是反映网络性能的一个重要指标。


我们知道,TCP 三次握手的过程客户端和服务器之间需要交互三次,那么也就是说需要消耗 1.5 RTT。

另外,如果使用的是安全的 HTTPS 协议,就还需要使用 TLS 协议进行安全数据传输,这个过程又要消耗一个 RTT(TLS 不同版本的握手机制不同,这里按照最小的消耗来算)

那么也就是说,一个纯 HTTP/2 的连接,需要消耗 1.5 个 RTT,如果是一个 HTTPS 连接,就需要消耗 3-4 个 RTT。

而具体消耗的时长根据服务器和客户端之间的距离则不尽相同,如果比较近的话,消耗在 100ms 以内,对于用来说可能没什么感知,但是如果一个 RTT 的耗时达到 300-400ms,那么,一次连接建立过程总耗时可能要达到一秒钟左右,这时候,用户就会明显的感知到网页加载很慢。

升级 TCP 是否可行?

基于上面我们提到的这些问题,很多人提出来说:既然 TCP 存在这些问题,并且我们也知道这些问题的存在,甚至解决方案也不难想到,为什么不能对协议本身做一次升级,解决这些问题呢?

其实,这就涉及到一个"协议僵化"的问题。

这样讲,我们在互联网上浏览数据的时候,数据的传输过程其实是极其复杂的。

我们知道的,想要在家里使用网络有几个前提,首先我们要通过运行商开通网络,并且需要使用路由器,而路由器就是网络传输过程中的一个中间设备。

中间设备是指插入在数据终端和信号转换设备之间,完成调制前或解调后某些附加功能的辅助设备。例如集线器、交换机和无线接入点、路由器、安全解调器、通信服务器等都是中间设备。

在我们看不到的地方,这种中间设备还有很多很多,一个网络需要经过无数个中间设备的转发才能到达终端用户。

如果 TCP 协议需要升级,那么意味着需要这些中间设备都能支持新的特性,我们知道路由器我们可以重新换一个,但是其他的那些中间设备呢?尤其是那些比较大型的设备呢?更换起来的成本是巨大的。

而且,除了中间设备之外,操作系统也是一个重要的因素,因为 TCP 协议需要通过操作系统内核来实现,而操作系统的更新也是非常滞后的。

所以,这种问题就被称之为"中间设备僵化",也是导致"协议僵化"的重要原因。这也是限制着 TCP 协议更新的一个重要原因。

所以,近些年来,由 IETF 标准化的许多 TCP 新特性都因缺乏广泛支持而没有得到广泛的部署或使用!

放弃 TCP?

上面提到的这些问题的根本原因都是因为 HTTP/2 是基于 TPC 实现导致的,而 TCP 协议自身的升级又是很难实现的。

那么,剩下的解决办法就只有一条路,那就是放弃 TCP 协议。

放弃 TCP 的话,就又有两个新的选择,是使用其他已有的协议,还是重新创造一个协议呢?

看到这里,聪明的读者一定也想到了,创造新的协议一样会受到中间设备僵化的影响。近些年来,因为在互联网上部署遭遇很大的困难,创造新型传输层协议的努力基本上都失败了!

所以,想要升级新的 HTTP 协议,那么就只剩一条路可以走了,那就是基于已有的协议做一些改造和支持,UDP 就是一个绝佳的选择了。

总结

因为 HTTP/2 底层是采用 TCP 协议实现的,虽然解决了 HTTP 队头阻塞的问题,但是对于 TCP 队头阻塞的问题却无能为力。

TCP 传输过程中会把数据拆分为一个个按照顺序排列的数据包,这些数据包通过网络传输到了接收端,接收端再按照顺序将这些数据包组合成原始数据,这样就完成了数据传输。

但是如果其中的某一个数据包没有按照顺序到达,接收端会一直保持连接等待数据包返回,这时候就会阻塞后续请求。这就发生了 TCP 队头阻塞

另外,TCP 这种可靠传输是靠三次握手实现的,TCP 三次握手的过程客户端和服务器之间需要交互三次,那么也就是说需要消耗 1.5 RTT。如果是 HTTPS 那么消耗的 RTT 就更多。

而因为很多中间设备比较陈旧,更新换代成本巨大,这就导致 TCP 协议升级或者采用新的协议基本无法实现。

所以,HTTP/3 选择了一种新的技术方案,那就是基于 UDP 做改造,这种技术叫做 QUIC。

那么问题来了,HTTP/3 是如何使用的 UDP 呢?做了哪些改造?如何保证连接的可靠性?UDP 协议就没有僵化的问题了吗?

这些问题我们在下一篇中深入分析。敬请期待!

参考资料:

http3-explained.haxx.se/

baike.baidu.com/item/中间设备/3…

time.geekbang.org/column/arti…

juejin.cn/post/684490…

time.geekbang.org/column/arti…

原文链接:https://juejin.cn/post/6905925275888926734

最后,小编还给大家整理了一份大厂面试突击宝典,有需要的添加小助理 vx:mxzFAFAFA 来领取~



发布于: 2021 年 04 月 28 日阅读数: 29
用户头像

领取文章中资料添加小助理vx:mxzFAFAFA 2021.02.05 加入

Java架构大数据每天分享干货!

评论

发布
暂无评论
HTTP/2做错了什么?刚刚辉煌2年就要被弃用了