第 1 章:为什么需要 QUIC——当 TCP 成为互联网的瓶颈
阅读门槛说明:本导读从日常场景出发,不要求你事先了解 QUIC 协议本身。但由于 QUIC 建立在网络协议栈之上,后续章节(尤其 ch03 起)会假设你具备 TCP/IP 基础概念(三次握手、序列号、丢包重传)。如果这些对你完全陌生,建议先花 1-2 小时过一遍任何一份”TCP/IP 入门”材料。导读总体 difficulty 标注为 advanced,指的是 目标深度(最终要能读懂 Rust 源码、写调度器),而非 起点要求。
一个你每天都在经历的场景
早高峰,你挤上地铁,打开手机继续看昨晚没看完的视频。地铁进站的时候信号还不错,用的是站台的 WiFi。列车一开动,手机自动切到 4G 信号。然后你就看到了那个让人抓狂的转圈圈——视频卡住了,进度条不动了,过了好几秒才恢复。
再想一个场景:你在宿舍用笔记本电脑打开一个网页,页面上有文字、图片、CSS 样式表、JavaScript 脚本。其中一张图片的数据包在网络传输中丢了,需要重传。按理说,文字和 CSS 已经到了,浏览器完全可以先渲染出来。但实际上,整个页面都在等那张丢失的图片——因为它们共享同一条 TCP 连接,一个数据包丢了,后面所有的数据都得排队等。
这两个问题,本质上都是 TCP 协议的设计局限。而 QUIC,就是为了解决这些问题而生的。
TCP:互联网的功臣,如今的瓶颈
TCP 是什么?一个日常类比
想象你要寄一个大型包裹给朋友。你把东西拆成 100 个小箱子,每个箱子贴上编号(1/100, 2/100…),然后交给快递公司。快递公司保证:
- 所有箱子都会到达(可靠传输)
- 按编号顺序交给你朋友(有序交付)
- 如果某个箱子丢了,会重新寄(重传机制)
这就是 TCP 的核心承诺。它在 1981 年被标准化(RFC 793),40 多年来一直是互联网传输层的基石。HTTP、HTTPS、SSH、FTP——几乎所有你日常使用的协议都建立在 TCP 之上。
TCP 的三大根本性限制
但 TCP 的设计是 40 年前的产物。当时的互联网是这样的:带宽以 Kbps 计算,网页只有纯文本,移动网络根本不存在。TCP 的设计假设是:连接两端的 IP 地址不会变,网络带宽很小不需要并行传输,安全性可以由上层协议(TLS)来处理。
这些假设在今天全都站不住脚了。
限制一:队头阻塞(Head-of-Line Blocking)
这是 TCP 最致命的问题。回到快递的类比:假设你朋友要求”必须按编号顺序开箱子”。箱子 1-50 已经到了,但箱子 51 在路上丢了。即使箱子 52-100 已经全部到达,你朋友也不能打开任何一个——他必须等箱子 51 被重新寄到。
在技术层面,TCP 是一个单一字节流。所有数据共享同一个序列号空间。当 Packet #51 丢失时,接收端的内核缓冲区里虽然已经有了 Packet #52-100 的数据,但它不会把这些数据交给应用层——因为 TCP 承诺有序交付。
HTTP/2 试图通过”多路复用”(Multiplexing)来解决这个问题:在一条 TCP 连接上同时传输多个 HTTP 请求/响应。但这只是应用层的优化——底层的 TCP 还是一条字节流。一个包丢了,所有流都被阻塞。这就是为什么 HTTP/2 在高丢包率网络下反而可能比 HTTP/1.1(每个请求一条连接)更慢。
TCP 队头阻塞示意图:
应用层看到的"多个流":
Stream A: [数据块1] [数据块2] [数据块3]
Stream B: [数据块1] [数据块2]
Stream C: [数据块1] [数据块2] [数据块3]
TCP 层实际传输(单一字节流):
[A1][B1][A2][C1][B2][A3][C2][C3]
↑
这个包丢了
↓
所有后续数据被阻塞,A2、C1、B2、A3、C2、C3 全部等待
限制二:连接建立慢(握手延迟)
TCP 建立连接需要三次握手(3-way handshake):
客户端 服务端
|------- SYN -------->| 第 1 次
|<----- SYN+ACK ------| 第 2 次
|------- ACK -------->| 第 3 次
| |
| (现在才能开始传数据) |
这要花 1 个 RTT(Round-Trip Time,往返时间)。如果你在北京访问一个美国的服务器,RTT 大约是 200ms,光建立 TCP 连接就要 200ms。
但这还没完。现代互联网几乎所有通信都要加密,需要在 TCP 之上再做 TLS 握手:
TCP 三次握手:1 RTT
TLS 1.2 握手:2 RTT(通常情况)
TLS 1.3 握手:1 RTT
─────────────────────────
总计:TCP + TLS 1.3 = 2 RTT
TCP + TLS 1.2 = 3 RTT
2-3 个 RTT,对于北京到美国的连接就是 400-600ms。用户要等半秒多才能看到第一个字节。在移动网络上,RTT 经常超过 100ms,这个延迟就更加明显了。
限制三:无法连接迁移
TCP 连接由四元组(source IP, source port, destination IP, destination port)唯一标识。当你的手机从 WiFi 切到 4G:
- 你的 IP 地址变了(从 WiFi 的 192.168.x.x 变成了运营商分配的公网 IP)
- 四元组变了
- 对服务端来说,这是一个”全新的设备”
- 旧连接失效,必须重新建立
这就是地铁里视频卡住的根本原因。TCP 没有”这个连接可以跟着我走”的概念——它把连接绑定在了网络地址上。
为什么不能直接”修”TCP?
你可能会想:既然 TCP 有这些问题,升级一下不就好了?
问题在于:TCP 已经”固化”在了整个互联网基础设施中。
路由器、防火墙、NAT 设备、运营商的中间件——这些设备都理解 TCP 报文格式,并且会对 TCP 进行各种”优化”(或者说干预)。如果你修改 TCP 的报文格式,这些中间设备可能会丢弃你的数据包,因为它们不认识新的格式。
这种现象叫做协议骨化(Protocol Ossification)。TCP 的报文头是明文的,中间设备可以看到并操作它。40 年间,全球数十亿网络设备已经形成了对 TCP 格式的依赖。想要升级 TCP,你需要升级全球所有的路由器和防火墙——这显然是不可能的。
Google 的工程师们想到了一个聪明的办法:绕过 TCP,在 UDP 上重新建造。
QUIC:从零开始的传输层协议
为什么选择 UDP 作为基础?
UDP(User Datagram Protocol)是互联网另一个基础传输协议。它非常简单——基本上就是”发出去就不管了”,不保证可靠、不保证有序、不做拥塞控制。
这正好是 QUIC 需要的。UDP 的好处是:
- 所有网络设备都认识 UDP——不会被防火墙拦截(大部分情况下)
- UDP 头部极其简单——只有 8 字节,没有什么可以被中间设备”干预”的
- UDP 不做任何假设——QUIC 可以在 UDP 之上自由实现自己的可靠性、有序性和拥塞控制
类比:TCP 就像坐公交车,路线是固定的(协议规则),你不能让司机改道。UDP 就像打车,你告诉司机目的地,怎么走你来决定。QUIC 选择了打车,然后自己当导航——它在 UDP 之上实现了比 TCP 更好的可靠传输。
QUIC 的四大核心承诺
承诺一:0-RTT 连接建立
QUIC 把传输层握手和加密握手合为一体。首次连接只需 1 RTT:
客户端 服务端
|--- Initial (含 TLS ClientHello) --->|
|<-- Initial (含 TLS ServerHello) ----| 1 RTT 后就能发数据
|--- Handshake + 应用数据 ----------->|
更厉害的是,如果你之前连接过这个服务器,QUIC 支持 0-RTT:
客户端 服务端
|--- Initial + 0-RTT 应用数据 ------->| 第一个包就带数据!
|<-- Initial + Handshake -------------|
第一个数据包就能携带应用数据!在用户的体验上,这意味着”瞬间”打开页面。
承诺二:无队头阻塞的多路复用
QUIC 原生支持多个独立的流(Stream)。每个流有自己的序列号空间,互不影响:
QUIC 多流传输:
Stream 0 (CSS): [帧1] [帧2] ✓ 到达即交付
Stream 2 (JS): [帧1] [帧2] [帧3] ✓ 到达即交付
Stream 4 (图片): [帧1] [✗丢失] [帧3] ← 只有这个流等重传
Stream 6 (HTML): [帧1] [帧2] ✓ 到达即交付
图片流的丢包不会影响 CSS、JS、HTML 的交付。浏览器可以先渲染文字和样式,图片晚一点再补上来。这就是 QUIC 解决队头阻塞的方式——在传输层就把”流”作为一等公民。
承诺三:连接迁移
QUIC 引入了 Connection ID(连接 ID)的概念。连接不再由 IP+端口标识,而是由一个随机生成的 ID 标识:
WiFi 网络下:
源 IP: 192.168.1.100, 端口: 12345
Connection ID: 0x1a2b3c4d
→ 服务端认识这个连接
切换到 4G:
源 IP: 10.0.0.50, 端口: 54321 ← IP 和端口都变了!
Connection ID: 0x1a2b3c4d ← 但 Connection ID 没变
→ 服务端说:"哦,还是你!"继续传数据
地铁里视频不再卡住——因为连接跟着你走,不跟着 IP 走。
承诺四:全程加密
QUIC 的报文头部大部分都是加密的。不像 TCP 的头部是明文的(中间设备可以看到序列号、窗口大小等),QUIC 只暴露极少量信息。这意味着:
- 中间设备无法干预 QUIC 的内部机制——防止协议骨化
- 窃听者看不到你在传输什么——天生隐私保护
- 未来升级协议不需要全球设备配合——保持可演进性
QUIC 的前世今生:从 Google 实验到国际标准
2012-2015:Google QUIC(gQUIC)
2012 年,Google 的 Jim Roskind 提出了 QUIC 的概念。最初它叫”Quick UDP Internet Connections”,是 Chrome 浏览器的一个实验性功能。Google 在自家的服务器和 Chrome 之间部署了 gQUIC,测试数据令人兴奋:
- YouTube 视频缓冲减少 30%
- Google 搜索延迟降低 8%(对 Google 来说这是巨大的数字)
- 在高丢包网络下性能提升更加显著
但 gQUIC 是 Google 的私有协议,使用了自己的加密方案(不是 TLS),格式也不公开。
2016-2021:IETF 标准化
2016 年,IETF(互联网工程任务组)开始标准化 QUIC。这是一个巨大的工程——把 Google 的私有实验变成所有人都能实现的公开标准。关键变化包括:
- 加密从 Google 自研方案改为 TLS 1.3
- 报文格式完全重新设计
- 拥塞控制从固定算法变为可插拔框架
- 多路径等扩展作为独立草案推进
2021 年 5 月:RFC 9000 发布
经过 5 年的讨论和 34 个草案版本,QUIC v1 正式成为互联网标准:
| RFC | 内容 |
|---|---|
| RFC 9000 | QUIC 传输协议核心 |
| RFC 9001 | QUIC 中的 TLS 使用 |
| RFC 9002 | QUIC 丢包检测与拥塞控制 |
| RFC 9369 | QUIC v2(密码学升级) |
2024-2025:多路径 QUIC
多路径 QUIC(Multipath QUIC)的标准化工作正在进行中(draft-ietf-quic-multipath)。这是 TQUIC 项目的核心方向——让一个 QUIC 连接同时使用 WiFi 和 4G,实现带宽聚合和无缝切换。
今天的 QUIC 已经在哪里?
你可能没意识到,但你每天都在用 QUIC:
- Google 全家桶:YouTube、Gmail、Google 搜索——Chrome 和 Google 服务之间的流量超过 50% 使用 QUIC
- HTTP/3:下一代 HTTP 协议(RFC 9114)就是建立在 QUIC 之上的
- Cloudflare:全球 CDN 默认启用 QUIC(使用他们自己的 quiche 实现)
- Meta(Facebook):内部服务大量使用 QUIC,mvfst 是他们的内部实现
- 腾讯:微信、QQ 视频通话使用 TQUIC
在浏览器里,你可以打开 chrome://net-internals/#quic 看看当前有多少连接在使用 QUIC。
六大开源实现:为什么不是只有一个?
标准有了,为什么会有 6 个(甚至更多)不同的实现?
因为设计空间太大了。RFC 9000 定义了协议的规则(”你必须这样做”),但在实现层面留下了大量选择:
| 选择 | 可选方案 |
|---|---|
| 编程语言 | Rust / C / C++ / Go / Python… |
| 架构模式 | sans-io / event-driven / kernel-integrated |
| 拥塞控制 | CUBIC / BBR / BBR2 / BBR3 / COPA |
| TLS 库 | BoringSSL / OpenSSL / rustls / GnuTLS |
| I/O 模型 | epoll / io_uring / XDP / 用户态 |
| 多路径 | 支持 / 不支持 |
这就像”造一辆车”的标准告诉你必须有四个轮子、方向盘、刹车,但没规定发动机用汽油还是电动、车身用钢材还是碳纤维。不同的实现根据自己的使用场景和设计理念做出不同的选择。
六个实现的一句话定位
| 项目 | Stars | 语言 | 一句话定位 |
|---|---|---|---|
| quiche | ~11.4K | Rust | Cloudflare 的生产级实现,sans-io 设计,CDN 规模验证 |
| msquic | ~9.7K | C | 微软的内核级实现,Windows/Linux 双平台,极致性能 |
| quinn | ~5.2K | Rust | 最简洁的 Rust 实现,学习 QUIC 源码的最佳入口 |
| s2n-quic | ~1.3K | Rust | AWS 的安全优先实现,每行代码追溯到 RFC |
| TQUIC | ~1.4K | Rust | 腾讯的多路径实现,唯一原生支持 Multipath QUIC |
| ngtcp2 | ~1.3K | C | curl 的 QUIC 后端,TLS 无关设计,万能适配器 |
为什么你应该关注 QUIC?
对于犀牛鸟参赛者
TQUIC 是犀牛鸟 2026 的项目之一。它的核心方向是多路径 QUIC——一个协议层面正在标准化、实现层面还很不成熟的领域。这意味着:
- 贡献机会多:多路径调度算法、路径管理、性能优化都有大量可做的事
- 技术壁垒适中:代码是 Rust,规模适中(~300 文件),有清晰的模块边界
- 影响力大:你的代码可能会用在微信和 QQ 的真实场景中
对于想进入网络领域的同学
QUIC 是过去 10 年传输层最大的变革。理解 QUIC 意味着:
- 你理解了现代互联网为什么比 10 年前更快
- 你理解了”协议设计”是怎么在工程中落地的
- 你有了看懂 RFC、读懂工业级代码的能力
对于想学 Rust 的同学
6 个实现中有 4 个用 Rust 写成(quiche, quinn, s2n-quic, TQUIC)。QUIC 实现是学习 Rust 系统编程的绝佳素材——它涉及异步、trait 设计、零拷贝、FFI、性能优化等几乎所有 Rust 的核心话题。
本章小结
| 问题 | 答案 |
|---|---|
| TCP 最大的问题是什么? | 队头阻塞、连接建立慢、无法迁移 |
| 为什么不直接升级 TCP? | 协议骨化——全球中间设备依赖 TCP 格式 |
| QUIC 建在什么上面? | UDP——所有设备都认识,且足够简单 |
| QUIC 的核心承诺? | 0-RTT、无 HOL 阻塞、连接迁移、全程加密 |
| 为什么有 6 个实现? | 设计空间大,不同场景有不同最优解 |
| TQUIC 的独特价值? | 唯一原生支持多路径 QUIC 的开源实现 |
读完本章你能做什么
- 能向不懂技术的朋友解释”为什么手机切网络时视频会卡”
- 能说出 TCP 的三个根本性限制
- 能解释 QUIC 为什么选择建在 UDP 之上
- 能列出 QUIC 的四大核心优势
- 能说出六个开源 QUIC 实现的名字和各自一句话定位
常见误区
误区一:QUIC 就是 “UDP + TLS”
正确理解:QUIC 在 UDP 之上重新实现了可靠传输(类似 TCP 的功能)+ 多路复用 + 连接管理 + 拥塞控制。TLS 1.3 只是其中的加密部分。把 QUIC 说成”UDP + TLS”,就像把汽车说成”轮子 + 发动机”——缺了太多东西。
误区二:QUIC 比 TCP 快是因为 UDP 比 TCP 快
正确理解:UDP 本身并不”快”——它只是不做任何处理就把数据丢出去。QUIC 快的原因是更好的连接建立(0-RTT)、消除了队头阻塞、以及更先进的拥塞控制算法。QUIC 在 UDP 之上做的可靠性保证并不比 TCP 少。
误区三:QUIC 会完全取代 TCP
正确理解:短期内不会。TCP 仍然适合很多场景(内网通信、长连接数据库、低延迟要求不高的场景)。而且很多防火墙仍然会阻拦 UDP 流量,QUIC 需要回退到 TCP 的能力。两者会长期共存。
章节自测
- 你在手机上刷短视频,坐地铁经过隧道时 WiFi 切到 4G。用 TCP 连接会发生什么?QUIC 的连接迁移如何避免这个问题?
- HTTP/2 已经支持多路复用了,为什么还有”队头阻塞”问题?QUIC 是怎么从根本上解决的?(提示:思考 TCP 层 vs 应用层的关系)
- 如果你要给一个企业内网系统加 QUIC 支持,最可能遇到的阻力是什么?你会如何说服运维团队?
导读目录:README.md 下一章:第 2 章 · 阅读路线图与前置知识