QUIC 协议栈与分层架构

聊 QUIC 之前,我习惯先把它放到 OSI 模型里看一眼。说白了,QUIC 是个「跨界」选手——它既干传输层的活,又管加密层的事,还顺手给应用层搭了把手。你想想看,传统协议栈里这三层是各管各的,QUIC 却把它们揉在了一起。

QUIC 在 OSI 模型中的位置

OSI 七层模型我们都很熟。TCP 在传输层(第4层),TLS 在表示层(第6层),HTTP 在应用层(第7层)。QUIC 呢?它横跨了传输层和表示层,甚至向上延伸到了应用层。

OSI 层 传统协议栈 QUIC 协议栈
应用层(7) HTTP/2 HTTP/3
表示层(6) TLS 1.3 QUIC 加密层(内置)
会话层(5) - QUIC 传输层(连接管理)
传输层(4) TCP QUIC 传输层(UDP 之上)
网络层(3) IP IP

注意看,QUIC 直接跑在 UDP 上,跳过了 TCP。这不是拍脑袋决定的——我在优化一个跨国视频会议项目时,TCP 的队头阻塞问题让我头疼了整整两周。换成 QUIC 后,问题迎刃而解。

核心观点:QUIC 把传输层和加密层合并到一个协议中,减少了握手轮次,也避免了传统分层带来的冗余开销。

QUIC 传输层与 HTTP/3 的关系

很多人搞混 QUIC 和 HTTP/3 的关系。我简单解释一下:QUIC 是传输协议,HTTP/3 是应用协议。HTTP/3 跑在 QUIC 之上,就像 HTTP/2 跑在 TCP 之上一样。

但有个关键区别——HTTP/3 不能直接跑在 TCP 上,它依赖 QUIC 提供的特性:

  • 多路复用无队头阻塞:一个连接里多个流独立传输,丢包只影响单个流
  • 0-RTT 握手:第二次连接时可以直接发数据
  • 连接迁移:切换网络时连接不断

我记得有一次调试一个移动端应用,用户从 Wi-Fi 切到 4G 时 TCP 连接全断了,所有请求都得重来。用 QUIC 后,连接 ID 不变,切换网络就像什么都没发生。

小提示:HTTP/3 的帧格式和 HPACK 压缩(升级为 QPACK)都针对 QUIC 的流模型做了重新设计。如果你从 HTTP/2 迁移,不能直接复用现有实现。

QUIC 协议栈的层次划分

QUIC 内部其实分三层:传输层、加密层、应用层。每一层各司其职,但又紧密耦合。我画了一张图,帮你理清它们的关系。

QUIC 协议栈分层架构 应用层 HTTP/3 · WebTransport · DNS-over-QUIC 流数据 · 帧封装 · QPACK 头部压缩 加密层 TLS 1.3 握手 · 密钥协商 · 数据加密 0-RTT · 连接迁移安全 · 防重放 传输层 连接管理 · 流多路复用 · 可靠传输 拥塞控制 · 丢包检测 · 连接迁移 UDP(底层传输) 应用 安全 传输

1. 传输层

这是 QUIC 的根基。它负责连接的建立、维护和关闭,管理多个流的并发传输,实现可靠交付和拥塞控制。我特别想强调一点:QUIC 的传输层是独立于加密层的,但实际实现中两者交互非常频繁。

  • 连接 ID:唯一标识一个 QUIC 连接,支持连接迁移
  • 流(Stream):轻量级的字节流,可独立发送数据
  • 帧(Frame):传输层的最小数据单元,如 STREAM 帧、ACK 帧
  • 拥塞控制:基于 NewReno、CUBIC 或 BBR 等算法

注意:QUIC 的传输层不保证数据顺序——这是故意的。每个流内部有序,但流之间可以乱序到达。我曾经见过有人用 QUIC 时还按 TCP 的思路等所有数据排好序再处理,结果白白增加了延迟。

2. 加密层

QUIC 把加密内建在协议里,而不是像 TCP+TLS 那样「外挂」。这意味着:

  • 握手阶段就加密——没有明文传输的中间状态
  • 所有数据包都加密,包括连接建立时的控制包
  • 0-RTT 数据也加密,但需要防重放攻击

我习惯把 QUIC 的加密层理解为「TLS 1.3 的深度定制版」。它用了相同的密码套件和握手流程,但针对 QUIC 的传输特性做了调整。举个例子,TLS 的 record 层在 QUIC 里被拆成了更细粒度的包,这样丢包时不需要重传整个 record。

3. 应用层

这一层是开发者直接打交道的。HTTP/3 是最典型的应用层协议,但 QUIC 不只服务于 HTTP:

应用协议 用途 特点
HTTP/3 Web 浏览 多路复用、0-RTT、连接迁移
WebTransport 实时通信 基于 QUIC 的 WebSocket 替代方案
DNS-over-QUIC 安全 DNS 查询 低延迟、防嗅探

应用层通过 QUIC 提供的 API 创建流、发送数据、接收事件。你不需要关心底层是 UDP 还是拥塞控制——这些都被传输层和加密层封装好了。

避坑指南:我曾经在实现 QUIC 应用层时犯过一个错——以为所有流都是平等的。实际上 QUIC 支持流优先级,HTTP/3 里请求的优先级直接影响页面加载性能。如果你不做优先级调度,关键资源可能被非关键资源阻塞。

三层如何协作?

用一个实际场景来说明:用户打开一个网页,浏览器发起 HTTP/3 请求。

  1. 传输层:创建 QUIC 连接,分配连接 ID,建立 UDP 套接字
  2. 加密层:执行 TLS 1.3 握手,协商密钥,加密后续所有数据
  3. 应用层:HTTP/3 在加密的流上发送请求帧,接收响应帧
  4. 如果网络切换(比如从 Wi-Fi 切到 5G),传输层通过连接 ID 保持连接,加密层不需要重新握手,应用层无感知

你看,三层各司其职,但又紧密配合。这也是 QUIC 能比 TCP+TLS+HTTP/2 快那么多的原因——不是某一层特别强,而是三层一起优化了整体流程。

个人经验:调试 QUIC 协议栈时,我建议从传输层开始。先确认连接建立、流创建、数据收发是否正常,再排查加密层的问题。加密层一旦出错,日志往往是乱码,很难直接定位。