这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战”
HTTP/2
为什么会出现HTTP/2?它相较于http1.1有哪些方面的提升?为什么出现HTTP/2?当然是因为HTTP/1.1太慢了。
HTTP/2相较于HTTP/1.1有哪些方面的提升?
- 二进制分帧层
HTTP/2 所有性能增强的核心在于新的二进制分帧层,它定义了如何封装 HTTP 消息并在客户端与服务器之间传输。
这里所谓的“层”,指的是位于套接字接口与应用可见的高级 HTTP API 之间一个经过优化的新编码机制
在二进制分帧层上,HTTP 2.0 会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码 ,其中HTTP1.x的首部信息会被封装到Headers帧,而我们的request body则封装到Data帧里面。
每个 HTTP 传输都承载一组标头,这些标头说明了传输的资源及其属性。 在 HTTP/1.x 中,此元数据始终以纯文本形式,通常会给每个传输增加 500–800 字节的开销。如果使用 HTTP Cookie,增加的开销有时会达到上千字节。
为了减少此开销和提升性能,HTTP/2 使用 HPACK 压缩格式压缩请求和响应标头元数据,这种格式采用两种简单但是强大的技术:
- 这种格式支持通过静态霍夫曼代码对传输的标头字段进行编码,从而减小了各个传输的大小。
- 这种格式要求客户端和服务器同时维护和更新一个包含之前见过的标头字段的索引列表(换句话说,它可以建立一个共享的压缩上下文),此列表随后会用作参考,对之前传输的值进行有效编码。
HTTP 2.0 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;通信期间几乎不会改变的通用键-值对(用户代理、可接受的媒体类型,等等)只需发送一次。事实上,如果请求中不包含首部(例如对同一资源的轮询请求),那么 首部开销就是零字节。此时所有首部都自动使用之前请求发送的首部。
- 多路复用
在HTTP/1.X中数据是基于文本的有序传输,不能并行传输而且接收端也不知道数据包的顺序。但HTTP/2 中新的二进制分帧层突破了这些限制,实现了完整的请求和响应复用: 客户端和服务器可以将 HTTP 消息分解为互不依赖的帧,然后交错发送,最后再在另一端把它们重新组装起来。
- 并行交错地发送多个请求,请求之间互不影响。
- 并行交错地发送多个响应,响应之间互不干扰。
- 使用一个连接并行发送多个请求和响应。
- 消除不必要的延迟和提高现有网络容量的利用率,从而减少页面加载时间
- 等等...
HTTP/2 中的新二进制分帧层解决了 HTTP/1.x 中存在的队首阻塞问题,也消除了并行处理和发送请求及响应时对多个连接的依赖。
- 数据流优先级
- 服务器推送
HTTP/2 新增的另一个强大的新功能是,服务器可以对一个客户端请求发送多个响应。 换句话说,除了对最初请求的响应外,服务器还可以向客户端推送额外资源,而无需客户端明确地请求。
HTTP/2的一些不足点
- 建立连接时间长,没办法,谁让它爸是TCP呢?我们知道,TCP三次握手的过程客户端和服务端之间需要交互三次,也就是说需要消耗1.5RTT,还有TLS加密握手,所以大概需要3RTT左右。而具体消耗的时长根据服务器和客户端之间的距离则不尽相同,如果比较近的话,消耗在100ms以内,对于用来说可能没什么感知,但是如果一个RTT的耗时达到300-400ms,那么,一次连接建立过程总耗时可能要达到一秒钟左右,这时候,用户就会明显的感知到网页加载很慢。
网络延迟又称为 RTT(Round Trip Time)。他是指一个请求从客户端浏览器发送一个请求数据包到服务器,再从服务器得到响应数据包的这段时间。RTT 是反映网络性能的一个重要指标。
- 队头阻塞问题。这里有同学会问,HTTP/2 不是解决了队头阻塞的问题吗?这里只说对了一半,HTTP/2 只解决了http消息队头阻塞问题,并没有解决TCP队头阻塞问题。
在远古的HTTP/1.1时代就存在队头阻塞问题,如果大家对于http的历史有一定了解的话,就会知道http1.1相较于HTTP/1.0最主要的改进就是引入了持久连接(keep-alive)。
所谓的持久连接:在一个TCP连接上可以传送多个http请求和响应,减少了简历和关闭连接的消耗和延迟。
另外,HTTP/1.1允许在持久连接上使用请求管道,是相对于持久连接的又一性能优化。
所谓请求管道,就是在HTTP响应到达之前,可以将多条请求放入队列,当第一条HTTP请求通过网络流向服务器时,第二条和第三条请求也可以开始发送了。在高时延网络条件下,这样做可以降低网络的环回时间,提高性能。
但是,对于管道连接还是有一定的限制和要求的,其中一个比较关键的就是服务端必须按照与请求相同的顺序回送HTTP响应。
这也就意味着,如果一个响应返回发生了延迟,那么其后续的响应都会被延迟,直到队头的响应送达。这就是所谓的HTTP队头阻塞。
HTTP队头阻塞问题在HTTP/2中得到了很好的解决,HTTP/2废弃了管道化大的方式,而引入帧、消息和数据流的概念,客户端和服务端可以把HTTP消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。
http2 虽然很好的解决了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队头阻塞,那么多个请求都会受到影响。
HTTP/3
既然HTTP/2有这么明显的缺点,大佬们就不会让他“苟活于世”呢?O(∩_∩)O哈哈~,这内卷tmd严重了~~~,这就是为什么HTTP/2问世才几年时间,更强大的HTTP/3就来了。
HTTP/3的一些增强点
通过上图我们可以看出,HTTP/3 中的 QUIC 协议集合了以下几点功能。
Tips: HTTP/3是基于QUIC建立的协议,所以也叫HTTP OVER QUIC
- 实现了类似 TCP 的流量控制、传输可靠性的功能。虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。
- 集成了 TLS 加密功能。目前 QUIC 使用的是 TLS1.3,相较于早期版本 TLS1.3 有更多的优点,其中最重要的一点是减少了握手所花费的 RTT 个数。
- 实现了 HTTP/2 中的多路复用功能。和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流(如下图)。实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题。
HTTP/3解决的一些痛点
我们再来看看HTTP/2的一些缺点以及QUIC是如何去解决的
- 连接时间长
前面说到 HTTP2 连接基本上要花到2~3个RTT才能完成连接,但QUIC基本上可以实现1或0RTT去完成连接的。如果是首次需要花1RTT去完成连接,但如果非首次连接0RTT就可以完成了,这是因为首次连接时会缓存配置文件,后续再连接时就可以直接使用,从而跳过1RTT,实现0RTT的业务数据交互。
- TCP队头阻塞
TCP协议在收到数据包之后,这部分数据可能是乱序到达的,但是TCP必须将所有数据收集排序整合后给上层使用,如果其中某个包丢失了,就必须等待重传,从而出现某个丢包数据阻塞整个连接的数据使用。
QUIC协议是基于UDP协议实现的,在一条链接上可以有多个流,流与流之间是互不影响的,当一个流出现丢包影响范围非常小,从而解决队头阻塞问题。
我们来看看HTTP/1.1、HTTP/2、QUIC怎么数据传输的。
HTTP/1.1
HTTP/2
QUIC
HTTP/3的一些挑战
通过上面的分析,我们相信在技术层面,HTTP/3 是个完美的协议。不过要将 HTTP/3 应用到实际环境中依然面临着诸多严峻的挑战,这些挑战主要来自于以下三个方面。
第一,从目前的情况来看,服务器和浏览器端都没有对 HTTP/3 提供比较完整的支持。Chrome 虽然在数年前就开始支持 Google 版本的 QUIC,但是这个版本的 QUIC 和官方的 QUIC 存在着非常大的差异。
第二,部署 HTTP/3 也存在着非常大的问题。因为系统内核对 UDP 的优化远远没有达到 TCP 的优化程度,这也是阻碍 QUIC 的一个重要原因。
第三,中间设备僵化的问题。这些设备对 UDP 的优化程度远远低于 TCP,据统计使用 QUIC 协议时,大约有 3%~7% 的丢包率。
关于 HTTP/3 的未来,我有下面两点判断:
- 从标准制定到实践再到协议优化还需要走很长一段路;
- 因为动了底层协议,所以 HTTP/3 的增长会比较缓慢,这和 HTTP/2 有着本质的区别
各位大佬给个star