背景:QUIC 是什么,为什么重要
现在我们访问网页走的几乎都是 TCP + TLS 的组合。这套方案运作了几十年,但问题也积累了几十年:TCP 的队头阻塞、握手延迟、网络切换时连接中断......这些问题在移动网络场景下尤为突出。
QUIC 是下一代网络传输协议,由 Google 最初提出,现已进入 IETF 标准化流程。它运行在 UDP 之上,内置 TLS 1.3 加密,默认加密传输,同时解决了 TCP 的多项历史遗留问题:
- 多路复用且没有队头阻塞(一个流的丢包不会卡住其他流)
- 连接迁移(换网络不断连)
- 握手延迟更低(0-RTT 或 1-RTT 建连)
HTTP/3 就是跑在 QUIC 之上的。可以说,QUIC 是当前 Web 传输层最重要的变革之一。
quiche:Cloudflare 的 Rust 实现
Cloudflare 在 2019 年开源了自己的 QUIC 协议实现,叫做 quiche(没错,就是法式咸派的拼法,和 QUIC 谐音)。这个库用 Rust 编写,托管在 GitHub 上。
这篇文章就是介绍 quiche 的设计思路,以及他们在实现过程中做的几个关键决策。
设计原则:只做协议,不碰 I/O
quiche 的核心设计原则是:库本身只处理 QUIC 协议逻辑,不碰网络 I/O。
具体来说,quiche 的 API 负责:
- 接收应用层传入的 UDP 数据包,解析处理
- 生成需要发出去的 QUIC 数据包,交还给应用层
但它不负责:
- 打开 socket
- 读写网络
- 管理事件循环
这么做的原因很实际:Cloudflare 的边缘网络栈大量代码是 C 写的,不可能把整个栈换成 Rust。quiche 需要能嵌入到 C 的环境里用,所以在 Rust API 之上额外暴露了一层 C 接口头文件,方便 C/C++ 及其他语言集成。
这个设计带来了很好的可复用性。quiche 被集成进了 Cloudflare 内部的 NGINX fork,也被 cURL 用来实验性地支持 QUIC。同时你也可以直接用它写 Rust 的 QUIC 客户端和服务端。
定时器的处理也遵循同样的思路:quiche 告诉应用层"你需要在 X 时刻醒来"(比如用于重传超时),但不自己管理定时器。应用层可以选择任何适合自己环境的方式来实现。
TLS 层:用 BoringSSL,但有讲究
QUIC 协议的握手直接使用 TLS 1.3,而不是像 HTTPS 那样 TLS 跑在 TCP 上。这带来了一个集成上的微妙问题。
普通 TLS 库的工作方式是:TLS 握手消息先经过 TLS 记录层的封装和保护,再交给传输层发出去。但 QUIC 不需要这一层,因为 QUIC 自己负责加密和传输,TLS 握手消息直接承载在加密的 QUIC 数据包里。
所以 quiche 需要一个能把原始 TLS 握手消息"暴露出来"的 TLS 库,不要记录层封装,不要额外保护。
Cloudflare 选择了 BoringSSL(Google 维护的 OpenSSL fork,他们几年前就迁过去了)。BoringSSL 专门为 QUIC 实现提供了对应的 API 接口,quiche 通过 Rust 的 FFI 机制调用它。
密码学层:ring 库,以及一个有意思的贡献
TLS 握手之外,QUIC 还需要处理数据包级别的加密。这部分 quiche 用的是 ring,一个 Rust 生态里很流行的密码学库,提供安全且高效的加密原语。
ring 和 BoringSSL 其实共享了部分底层的高性能密码学算法实现,但 ring 对外暴露的是更符合 Rust 风格的安全 API。
这里有一个细节值得说:QUIC 的加密方式比较特殊。数据包的 payload 加密用的是标准的 AEAD 算法(AES-GCM 或 ChaCha20-Poly1305),这很常见。但数据包 header 的保护用了一套专门为 QUIC 设计的机制,目的是防止网络中间设备(middlebox)读取包头里的元数据(比如包序号)。
Header 保护所需的密码学原语,在 ring 库里原本没有。quiche 团队为此给 ring 提了 PR,把这部分补上了,最终随 ring v0.14.0 正式发布,成为开源贡献的一部分。
现状与后续
quiche 第一次提交距这篇文章发布只有三个月,但已经能和其他更成熟的 QUIC 实现互通,验证了协议的大多数核心特性。
作者也坦诚地说:quiche 和 QUIC 本身一样,都还没有"完成"。协议在标准化过程中还会继续演进,实现里的 bug 会被发现和修复,API 也可能随着经验积累而调整。
几点值得关注的设计取舍
读完这篇博客,有几个设计决策值得单独拎出来说:
不碰 I/O 的边界划分是最核心的一条。这个决定让 quiche 既能在 Rust 项目里用,也能被 C 栈集成,大幅拓宽了使用场景。对于要写协议库的人来说,这是一个很值得参考的思路:把协议状态机和 I/O 彻底分开。
FFI 集成是 Rust 库嵌入 C 生态的标准路径。quiche 在 Rust API 外单独维护了一个 C 头文件,这个做法在需要跨语言集成时很常见,Rust 生态里这类库不少。
给上游库贡献缺失的原语,而不是自己另起炉灶------这在工程上是更好的选择,维护成本更低,也让整个生态受益。
小结
quiche 这个项目本身不复杂,代码量也不大,但它背后的工程判断值得细品:清晰的边界、务实的语言选型、对上游的贡献而非 fork。
对于关注网络协议、Rust 系统编程或者基础设施工程的人来说,quiche 的源码是个不错的阅读材料。QUIC 已经是现实中跑在生产上的协议,HTTP/3 的普及也在持续推进,理解它的实现细节,会越来越有用。
原文地址:https://blog.cloudflare.com/enjoy-a-slice-of-quic-and-rust/