HTTP/3 的 QUIC 基于 UDP,为什么仍然可靠?

QUIC 并不是裸用 UDP,而是在 UDP 之上实现确认、丢包恢复、流量控制、拥塞控制、加密握手、多路复用和连接迁移。理解这 7 点,才能把 HTTP/3 的可靠性讲清楚。

HTTP/3 的 QUIC 基于 UDP,为什么仍然可靠?

先说结论

面试官问“HTTP/3 的 QUIC 基于 UDP,那它是不是不可靠?”时,最危险的回答是直接说“UDP 不可靠,所以 QUIC 也不可靠”。

更准确的回答是:QUIC 使用 UDP 作为承载层,但并不是把业务数据裸奔在 UDP 上。UDP 只负责尽力投递数据报,真正的连接管理、确认应答、丢包检测、重传、流量控制、拥塞控制、加密握手和连接迁移,都是 QUIC 自己在协议层实现的。

所以 HTTP/3 不是牺牲可靠性换性能,而是在保留可靠传输能力的前提下,减少连接建立延迟,并缓解 TCP 在多路复用场景下的队头阻塞。

为什么“基于 UDP”不等于“不可靠”

UDP 本身确实不保证可靠投递:它不保证数据一定到达,不保证顺序,也不负责重传。但协议栈的能力不是只能放在内核里的 TCP 层实现。QUIC 的设计思路是:把 UDP 当成一个更容易穿透网络设备的承载通道,然后在 QUIC 层重新定义可靠传输所需的状态机。

这也是面试里应该讲清楚的第一层逻辑:

  • UDP 提供的是数据报承载能力。
  • QUIC 提供的是面向连接的可靠传输能力。
  • HTTP/3 使用 QUIC 作为传输层,而不是直接使用裸 UDP。

换句话说,QUIC 的可靠性不是 UDP 送的,而是 QUIC 自己补上的。

保障一:包编号和 ACK,知道哪些包到了

TCP 依靠序列号和 ACK 来判断字节流是否被对端确认。QUIC 也有自己的确认机制,但它用的是 packet number,也就是包编号。

发送方发出的 QUIC 包会带有包编号。接收方收到后,通过 ACK frame 告诉发送方哪些包已经收到。这样即使底层 UDP 不提供确认,QUIC 仍然可以维护自己的发送状态和接收状态。

这一步解决的是“可观测性”问题:发送方不能只管发,还要知道哪些数据已经被对端确认,哪些数据长时间没有确认。

保障二:丢包检测和重传,丢了不会无声消失

有了包编号和 ACK,QUIC 就可以判断丢包。比如发送方发出 1、2、3、4、5 号包,接收方确认了 1、2、4、5,却迟迟没有确认 3,发送方就可以根据包阈值、时间阈值和 RTT 估计判断 3 号包可能丢了。

这里有一个很重要的细节:QUIC 重传的通常不是“原始 UDP 数据报本身”,而是丢失包里承载的可重传 frame 数据。它可以把这些 frame 重新装进新的 QUIC 包里再发送,并分配新的 packet number。

这个设计比“把原包原样再发一遍”更灵活。因为网络状态、加密级别、拥塞窗口、发送队列都可能已经变化,重新打包能让 QUIC 更好地配合当前连接状态。

保障三:多 Stream 独立排序,缓解队头阻塞

HTTP/2 已经支持在一个连接里多路复用多个请求,但它底层仍然依赖 TCP。TCP 暴露给上层的是一个有序字节流,只要前面的 TCP 段丢了,后面的字节即使已经到达,也不能被上层越过使用。

这就是 HTTP/2 over TCP 很典型的传输层队头阻塞:一个包丢失,可能拖住同一条 TCP 连接上的多个 HTTP/2 stream。

QUIC 的处理方式不同。一个 QUIC connection 内可以承载多个 stream,每个 stream 有自己的偏移量、排序和重传逻辑。某个 stream 的数据丢了,主要影响这个 stream 自己;其他 stream 已经到达的数据,不必因为它停住。

举个直观例子:同一条 QUIC 连接里,一个视频片段请求发生丢包,不应该拖住旁边一个接口请求的响应。QUIC 的多 stream 机制就是为这种场景降低相互影响。

保障四:连接级和 Stream 级流量控制,防止接收端被打爆

可靠传输不只是“丢了重发”,还要防止发送方发得太快,把接收方缓冲区撑爆。QUIC 提供两层流量控制:

  • 连接级流量控制:限制整个 connection 上最多可以发送多少未被接收方允许的数据。
  • Stream 级流量控制:限制单个 stream 最多可以发送多少数据。

这两层控制解决的问题不一样。连接级限制保护整个连接的接收资源;stream 级限制防止某一个大流量 stream 抢占所有缓冲区。

面试时可以把它总结成一句话:QUIC 不仅要保证数据能到,还要保证发送方不能不受控地把接收方压垮。

保障五:拥塞控制,防止把网络链路打爆

流量控制保护的是接收端,拥塞控制保护的是网络链路。

QUIC 会根据 ACK、丢包、RTT 等信号判断网络是否拥塞,并动态调整发送速率。网络状态好时,发送窗口可以扩大;出现丢包、延迟升高或拥塞信号时,发送方要收缩发送节奏。

这点和 TCP 的工程目标相似:不能因为应用层想多发,就无限制地向网络灌数据。QUIC 的规范把丢包检测和拥塞控制独立成 RFC 9002,实际实现也可以采用不同算法,例如 Cubic、BBR 等。

需要注意的是,拥塞控制不等于流量控制。前者看网络,后者看接收方,两者都属于 QUIC 可靠传输体验的一部分。

保障六:默认集成 TLS 1.3,加密和握手合在一起

传统 HTTPS 通常是先建立 TCP 连接,再进行 TLS 握手。QUIC 则把传输握手和 TLS 1.3 加密握手结合在一起,连接建立路径更短。

这带来两个直接结果:

第一,HTTP/3 的连接建立延迟可以更低。尤其是在重复连接场景下,QUIC 可以利用 TLS 1.3 的能力缩短恢复连接所需的交互。

第二,QUIC 默认加密,而且不只是加密业务数据。QUIC 的许多传输控制信息也受到保护,减少中间设备对协议行为的误判、篡改或僵化依赖。

当然,加密本身不是“可靠投递”的同义词。它保障的是安全性、完整性和抗干扰能力;和 ACK、重传、流控、拥塞控制放在一起,才构成 HTTP/3 更完整的传输体验。

保障七:Connection ID,支持连接迁移

TCP 连接通常依赖四元组识别:源 IP、源端口、目标 IP、目标端口。移动端从 Wi-Fi 切到蜂窝网络时,源 IP 和端口可能变化,原 TCP 连接往往就断了。

QUIC 使用 connection ID 来识别连接。只要对端可以验证新的路径仍然属于同一个连接,IP 和端口变化并不必然导致连接中断。

这就是 QUIC 连接迁移的价值。它不是让网络切换完全无感,也不是保证任何弱网都不会中断,而是给协议提供了“网络路径变化后继续复用原连接状态”的能力。对移动端、弱网和网络切换频繁的场景,这一点非常关键。

面试时怎么答

如果面试官只要求一句话,可以这样回答:

QUIC 虽然基于 UDP,但它不是裸用 UDP,而是在 QUIC 层实现了可靠传输能力,包括 packet number 与 ACK 确认、丢包检测与 frame 重传、连接级和 stream 级流量控制、拥塞控制、多 stream 独立传输、TLS 1.3 默认加密,以及基于 connection ID 的连接迁移。

如果面试官继续追问“那 QUIC 和 TCP 的可靠性有什么区别”,可以补一句:

TCP 保证的是单一有序字节流的可靠传输;QUIC 保证的是连接内多个 stream 的可靠传输,并把丢包恢复、加密握手和连接迁移做进了协议本身,所以它能在 HTTP/3 场景下减少连接延迟和传输层队头阻塞。

容易说错的点

第一,不要说“QUIC 因为基于 UDP 所以不可靠”。UDP 不可靠,但 QUIC 自己实现了可靠传输机制。

第二,不要说“QUIC 消灭了所有队头阻塞”。QUIC 缓解的是 TCP 传输层队头阻塞;单个 stream 内部仍然需要有序交付,应用层也可能有自己的依赖关系。

第三,不要把流量控制和拥塞控制混为一谈。流量控制保护接收方,拥塞控制保护网络。

第四,不要把 TLS 1.3 说成单纯的性能优化。它同时影响安全、握手、密钥派生和传输控制信息保护。

第五,不要说“连接迁移只靠 connection ID 就一定成功”。Connection ID 是基础,真实迁移还需要路径验证、拥塞状态处理和实现层面的配合。

最后记住这一句

QUIC 的核心不是“UDP 比 TCP 快”,而是“用 UDP 承载,在 QUIC 层重新实现更适合 HTTP/3 的可靠传输”:既保留确认、重传、流控和拥塞控制,又通过多 stream、TLS 1.3 和 connection ID 改善连接延迟、队头阻塞和移动网络切换体验。

参考资料

上一篇:Superpowers:把 AI 编程从提示词技巧升级成工程流程 下一篇:百万在线 IM 已读未读怎么设计?

评论

评论(0)

暂无评论