丢包≠堵车
BBR 给 TCP 换了一套神经系统——不去撞墙,直接测量瓶颈。三十年「丢包即拥塞」的假设,被两个数推翻。
序 · 困境
你在机场连上 Wi-Fi,信号满格,网页十秒打不开
那根光纤能跑 10Gbps——但 TCP 自己把路堵死了。1988 年 Van Jacobson 设计拥塞控制时,路由器只有几 KB 缓冲区,丢包确实等于拥塞。三十年过去,网卡 Gbps、内存 GB,丢包和拥塞的关系早已断裂——但 TCP 还在靠撞墙判断路况。
当瓶颈缓冲区大时,基于丢包的 CUBIC 不停往里塞,塞到溢出才停——队列装满,延迟爆炸。这叫 bufferbloat。
当瓶颈缓冲区小时,随机无线丢包被误判为拥塞——吞吐暴跌。
BBR 问了一个不同的问题:不去看拥塞的后果(丢包),直接去测量拥塞发生的那个位置——瓶颈链路的容量和传播延迟。
01 · 核心机制
两个数,描出一条路
CUBIC 靠撞墙(丢包)判断路况,BBR 直接测量道路本身:最快能跑多快?路有多长?
-
BtlBw瓶颈带宽 · Bottleneck Bandwidth
过去 10 个往返内网络交付数据的最大速率。不是发多快,是对方收多快。那个峰值就是这条路的速度上限。每次 ACK 回来都产生一个速率采样,窗口最大滤波器自动跟踪上限。
-
RTprop往返传播时间 · Round-Trip Propagation Time
数据在空路上往返的最短时间——物理距离的耗时,不含排队。过去 10 秒内的最小 RTT。只要路上有排队,RTT 就会被抬高;只有把队列清空时测到的才是真正的传播延迟。
-
BDP带宽延迟积 · Bandwidth-Delay Product
BDP = BtlBw × RTprop,恰好填满管道的数据量。1979 年 Kleinrock 就证明这是吞吐与延迟同时最优的操作点:再多一点,数据开始排队,延迟变坏;再少一点,带宽浪费。
-
那条著名曲线Figure 1 · RTT / Delivery Rate vs Inflight
横轴是空中数据量(inflight),纵轴是 RTT 和交付速率。inflight < BDP 时速率随 inflight 线性增长,RTT 恒定(没排队)。inflight > BDP 时速率不再增长,RTT 线性攀升(开始排队)。继续塞到爆 → 丢包。BBR 要做的就是让 inflight 始终逼近 BDP 那个点:吞吐最大、延迟最小——两个目标同时达到。
02 · 状态机
四步找到并守住那个最佳点
BBR 用四个状态在 BDP 最优操作点附近巡航。每个状态解决一个具体问题。
①
STARTUP 起步
像新人走进空高速,油门踩到底——但用交付速率来判断是否到了瓶颈,而不是等撞墙。
增益 2/ln2 ≈ 2.89②
DRAIN 排空
起步太快积了一堆排队数据。这时减速,把队列慢慢放掉,让 inflight 回到 BDP 附近。
增益 0.35③
PROBE_BW 巡航
大部分时间按瓶颈速率发送。每隔 8 个往返穿插一次加速探测(1.25×)和一次让路(0.75×),持续发现新带宽。
周期 [1.25, 0.75, 1×6]④
PROBE_RTT 重测
超过 10 秒没刷新 RTprop?主动把 inflight 降到 4 个包,强制清空所有队列,重新量一遍真正的传播延迟。只需 200ms。
inflight → 4 包03 · 设计哲学
BBR 翻转了四个网络默认假设
这些原则不仅适用于拥塞控制,也是自适应系统的通用思维。
-
01
测量代替猜测 CUBIC 靠丢包事件的频率间接推断拥塞。BBR 直接测量瓶颈带宽和传播延迟——在事件发生之前就知道系统状态。
-
02
模型驱动而非事件驱动 维护一个持续更新的路径模型(BtlBw + RTprop),行为锚定在模型上,而不是被动响应丢包和超时。
-
03
吞吐与延迟可以兼得 在 BDP 点,吞吐最大同时延迟最小。之前的拥塞控制认为二者是矛盾——BBR 证明这个矛盾是虚构的。
-
04
排队不是资源,是债 缓冲区不是吞吐的来源——带宽才是。队列只是延迟。把 inflight 控制在 BDP 以内,不需要大缓冲区。
04 · 实绩
YouTube 全球部署后的效果
BBR 不仅更快,而且不堵。Google 在全球最大的视频平台上验证了这套算法。
05 · 洞见
这篇论文真正找到的思想结晶
拥塞控制的正确信号不是丢包,是瓶颈本身。测量它,适应它,而不是等它溢出之后才反应。把「拥塞控制」从「损失控制」变回「拥塞控制」——这是对三十年网络直觉的一次校正。
06 · 启发
这篇论文的思想可以带到哪里
BBR 的核心思维——持续测量环境上限,行为锚定在测量结果上——是一种通用的自适应策略。
-
迁移API 限流 · 连接池 · 消息队列
任何需要自适应速率的系统:与其在收到 429 或超时后退避,不如主动测量服务端的处理速率上限,把请求速率锚定在那个值附近。记录每次请求完成时间,维护窗口内完成速率最大值和延迟最小值,在速率拐点处停下。
-
混搭应用层并发自调节器
请求处理的最佳并发数 = 处理速率 × 平均延迟(应用层的 BDP)。做一个运行时自调节器:持续测量处理吞吐和平均延迟,自动调整并发度到乘积附近。偶尔多开一点探测上限(PROBE_BW 思想),偶尔少开一点让队列排空。
-
反转排队不是资源,是债
别在应用层乱加队列——消息队列缓冲、线程池工作队列、数据库写入缓冲。每加一层队列,就加了延迟,但没有加吞吐。用背压替代队列,让上游在源头减速,而不是在下游排队。
07 · FAQ
你可能想问
- BBR 和 CUBIC 的核心区别是什么?
- CUBIC 是丢包驱动的:靠丢包事件推断拥塞,在缓冲区满和半满之间振荡。BBR 是模型驱动的:直接测量瓶颈带宽和传播延迟,在 BDP 最优操作点附近巡航——延迟低、吞吐高、不靠丢包。
- BBR 在丢包严重的无线网络上表现如何?
- 这是 BBR 相比丢包算法的最大优势之一。CUBIC 碰到无线随机丢包会误判为拥塞并降速;BBR 不把丢包当拥塞信号,所以在丢包率高达 20% 的网络上依然能跑满带宽。
- 如何在 Linux 上启用 BBR?
echo bbr > /proc/sys/net/ipv4/tcp_congestion_control(需要 Linux 4.9+)。也可以持久化:net.core.default_qdisc = fq+net.ipv4.tcp_congestion_control = bbr写入/etc/sysctl.conf。BBR 要求配合 fq(Fair Queue)qdisc 使用。- BBR 有几个版本?
- BBRv1(2016,本文):纯模型驱动,不看丢包。BBRv2(2019):加入丢包和 ECN 信号,改善与 CUBIC 的公平性。BBRv3(2023):修复 v2 两个 bug,性能调优。还有 BBR.Swift,为数据中心内链路优化。
- BBR 的缺点是什么?
- v1 与 CUBIC 共存时公平性有争议——在某些场景下 BBR 会挤占 CUBIC 流的带宽。v2/v3 已大幅改善。此外,BBR 在蜂窝等剧烈波动环境中的表现不如专用方案。
更多技术细节见 Google Research 论文页 与 github.com/google/bbr。