HTTP/3
HTTP2的缺陷
-
TCP队头阻塞
-
TCP 与 TLS 的握手时延迟
- TCP 三次握手和 TLS 四次握手(TLS 1.2)的过程需要 3 个 RTT 的时延
- 拥塞控制「慢启动」过程,它会对 TCP 连接产生“减速”效果。
-
网络迁移需要重新连接
- IP 地址或者端口变动了,就会导致需要 TCP 与 TLS 重新握手
QUIC 协议
使用UDP:
-
顺序、可靠性:数据包唯一标识
-
无队头阻塞
- 在同一条连接上并发传输多个 Stream,Stream 可以认为就是一条 HTTP 请求。
- 当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。
-
更快的连接建立
- QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS 1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。
-
连接迁移
- UDP 连接 ID 来标记通信的两个端点,网络IP 地址变化,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接
HTTP/3 协议
- HTTP/3 同 HTTP/2 一样采用二进制帧的结构
- 不同的地方在于 HTTP/2 的二进制帧里需要定义 Stream,而 HTTP/3 自身不需要再定义 Stream,直接使用 QUIC 里的 Stream,于是 HTTP/3 的帧的结构也变简单了。
-
Headers 帧(HTTP 头部)
-
头部压缩算法升级成 QPACK,也采用了静态表、动态表及 Huffman 编码:
- 静态表扩大到 91 项
- Huffman 编码并没有多大不同
- 动态表编解码方式不同
-
-
DATA 帧(HTTP 包体)属于数据帧。
动态表编解码改进
Why?
动态表时序性的,如果首次请求丢包,后续请求,无法解码HPACK 头部,后续的请求解码会阻塞到首次请求中丢失的数据包重传过来。
How?
QUIC 会有两个单向流的用法:
- QPACK Encoder Stream:将一个字典(Key-Value)传递给对方,比如面对不属于静态表的 HTTP 请求头部,客户端可以通过这个 Stream 发送字典;
- QPACK Decoder Stream:响应对方,告诉它刚发的字典已经更新到自己的本地动态表了,后续就可以使用这个字典来编码了。
用来同步双方的动态表,编码方收到解码方更新确认的通知后,才使用动态表编码 HTTP 头部。