QUIC
需要 HTTP/3 的主要原因是为了解决 HTTP/1.1 和 HTTP/2 在使用 TCP 协议时遇到的性能瓶颈和限制,尤其是在存在丢包和网络切换的情况下。
以下是需要 HTTP/3 的几个关键原因:
解决 TCP 的队头阻塞 (Head-of-Line Blocking - HOLB) 问题:
- HTTP/1.1 的 HOLB: 在 HTTP/1.1 中,即使开启了 Pipelining(尽管实际应用中问题很多),在一个连接上,前一个请求的响应必须完全接收后,下一个请求的响应才能开始发送。如果中间某个请求或响应被阻塞,后续的所有请求都会被延迟。
- HTTP/2 的 TCP HOLB: HTTP/2 通过多路复用(Multiplexing)解决了应用层的 HOLB,允许在同一个 TCP 连接上同时发送多个请求和接收多个响应。然而,HTTP/2 仍然运行在 TCP 协议之上。TCP 是一个保证可靠和有序传输的协议,它要求数据包按顺序到达。如果在传输过程中,某个 TCP 数据包丢失了,TCP 会暂停整个连接的数据传输,直到丢失的数据包被重传并正确插入到序列中。这意味着,即使丢失的数据包只影响到 HTTP/2 连接中的某一个流(Stream),整个连接上的所有其他流都会被这个丢包事件阻塞,等待重传完成。这就是 TCP 层的队头阻塞,它极大地影响了 HTTP/2 在丢包环境下的性能。
- HTTP/3 (基于 QUIC) 的解决方案: HTTP/3 使用了基于 UDP 的 QUIC 协议。QUIC 在应用层实现了类似 TCP 的可靠传输、流量控制和拥塞控制,但它是基于“流”来管理的。每个 HTTP 请求都被分配到一个独立的 QUIC 流。即使一个流中的数据包丢失,只会阻塞该流的传输,而同一连接上的其他流可以继续独立地传输数据,不会受到影响。这彻底解决了 TCP 层的 HOLB 问题,显著提升了在丢包率较高或网络不稳定的环境下的性能。
更快的连接建立:
- TCP + TLS 连接建立: 传统的 HTTPS 连接需要先进行 TCP 的三次握手(1.5个 RTT),然后再进行 TLS 的握手(1到2个 RTT),总共需要 2.5 到 3.5 个 RTT 才能开始传输应用数据,增加了延迟。
- QUIC 的 0-RTT 和 1-RTT 连接建立: QUIC 将连接建立和 TLS 握手(QUIC 集成了 TLS 1.3)结合在一起。对于首次连接,通常只需要 1 个 RTT 就可以完成握手并开始传输加密的应用数据。对于非首次连接(客户端保留了先前的连接信息),在很多情况下可以实现 0-RTT 握手,客户端发送的第一个包就可以包含应用数据,大大降低了连接建立的延迟。
改进的网络切换能力:
- TCP 的连接识别: TCP 连接是由源 IP、源端口、目标 IP、目标端口这四个元素唯一确定的。如果客户端在连接过程中更换了网络(例如从 Wi-Fi 切换到蜂窝数据),其 IP 地址或端口会改变,导致 TCP 连接必须中断并重新建立。
- QUIC 的连接 ID: QUIC 使用一个独立的连接 ID 来标识一个连接,而不是依赖于 IP 地址和端口号。这意味着,即使客户端的网络地址发生变化,只要客户端能够在新的网络下使用相同的连接 ID 与服务器通信,原有的 QUIC 连接就可以继续维持,而无需重新建立,这对移动设备的无缝切换网络非常有利。
更灵活的拥塞控制:
- TCP 的拥塞控制算法通常在操作系统内核中实现,更新和部署新的算法比较困难。
- QUIC 的拥塞控制则在应用层实现,可以更灵活地选择和部署不同的拥塞控制算法,以便更好地适应不同的网络环境。
总结来说,需要 HTTP/3 是为了构建一个更加高效、低延迟和鲁棒的网络传输层,特别是在移动和无线网络环境下,通过使用基于 UDP 的 QUIC 协议,彻底解决了 TCP 队头阻塞问题,加快了连接建立,增强了网络切换的平滑性,从而提供更快的网页加载速度和更好的用户体验。