youyichannel

志于道,据于德,依于仁,游于艺!

0%

HTTP 的演化历程

HTTP/0.9 -> HTTP/1.0 -> HTTP/1.1 -> HTTP/2 -> HTTP/3,一代更比一代强,一浪更比一浪强,前浪拍死在沙滩上!

HTTP/0.9 -> HTTP/1.0

参考 MDN-HTTP 的发展

HTTP/1.0 -> HTTP/1.1

HTTP/1.1 相比 HTTP/1.0 在性能上的改进

  • 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销;
  • 支持管道网络传输,即请求可以连续发送,不需要等待前一个请求的响应,这可以减少整体的响应时间。

HTTP/1.1 的性能瓶颈

  • 请求 / 响应头部较重,未经压缩就发送,首部信息越多延迟越大;
  • 每次都要发送冗长的首部,浪费资源;
  • Server 是按照请求的顺序响应的,如果 Server 响应慢,会导致 Client 一直得不到响应,造成队头阻塞;
  • 没有请求优先级控制;
  • 请求只能从 Client 开始,Server 不能够主动推送,只能够被动响应。

HTTP/1.1 -> HTTP/2

HTTP/2 基于 HTTPS 的,因此 HTTP/2 在安全性是有保障的。

HTTP/2 相比 HTTP/1.1 在性能上的改进

1)头部压缩

Security and performance of HPACK

HTTP/2 使用 HPACK 算法压缩头部信息,做法是在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,之后请求只发送索引号,提高效率。

2)二进制格式

Binary framing layer

HTTP/2 报文是以二进制格式,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧(Headers Frame)和数据帧(Data Frame),提高了数据传输的效率,

3)并发传输

Request and response multiplexing

1 个 TCP 连接包含多个 Stream,Stream 里可以包含 1 个或多个 Message,Message 对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成。Message 里包含一条或者多个 Frame,Frame 是 HTTP/2 最小单位,以二进制压缩格式存放 HTTP/1 中的内容(头部和包体)。

针对不同的 HTTP 请求用独一无二的 Stream ID 来区分,接收端可以通过 Stream ID 有序组装成 HTTP 消息,不同 Stream 的帧是可以乱序发送的,因此可以并发不同的 Stream ,也就是 HTTP/2 可以并行交错地发送请求和响应

4)服务器主动推送资源

Server push

HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务端不再是被动地响应,可以主动向客户端发送消息。

客户端和服务器双方都可以建立 Stream, Stream ID 也是有区别的,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号。

HTTP/2 的缺陷

HTTP/2 虽然解决了应用层的队头阻塞,但是在传输层,也就是 TCP 层还是存在「队头阻塞」的问题。

HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。

HTTP/2 -> HTTP/3

HTTP/3 是基于 UDP 协议的,也就是 QUIC 协议。

QUIC 协议的特点

1)无队头阻塞

QUIC 协议也有 Stream 与多路复用的概念,也是可以在同一条连接上并发传输多个 Stream,Stream 可以认为就是一条 HTTP 请求。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。因此,QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其他流不受影响。

2)更快的连接建立

对于 HTTP/1 和 HTTP/2 协议而言,TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手,再 TLS 握手。而 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是 QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS/1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商。在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。

3)连接迁移

基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。那么当移动设备的网络切换时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立连接,而建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,用户的感觉就是网络突然卡顿了一下,因此连接的迁移成本是很高的。

而 QUIC 是通过连接 ID 来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。