TCP BBR 拥塞控制算法是什么?相比传统的 CUBIC 好在哪?
简化版
BBR(Bottleneck Bandwidth and RTT)是 Google 提出的 TCP 拥塞控制算法,核心思路是**「主动测量瓶颈带宽和最小 RTT,据此把发送速率精准控制在链路的实际容量附近」,而不像传统算法那样把丢包当作拥塞信号**。传统的 CUBIC/Reno 是「基于丢包」 的:一直加速直到把缓冲区塞满、丢包了才降速——这有两个毛病:① 在有随机丢包的链路(无线、跨国)上,会把非拥塞的丢包误判成拥塞而无谓降速,吞吐上不去;② 会把网络缓冲区填满才罢休,导致排队延迟飙升(Bufferbloat)。BBR 直接估算「带宽 × RTT = BDP」作为在途数据的目标量,既能跑满带宽,又不把缓冲区填爆,所以在高延迟、有丢包的链路上吞吐更高、延迟更低。它是长肥管道和跨国传输的常用优化。
详细版
一、拥塞控制要解决什么
网络中间的路由器有缓冲区,发太快会排队 → 延迟涨 → 溢出丢包。拥塞控制就是发送方动态调节发送速率/窗口,既不压垮网络,又尽量跑满带宽。分两大流派:
| 流派 | 代表 | 判断拥塞的信号 |
|---|---|---|
| 基于丢包 | Reno、CUBIC | 丢包 = 拥塞(丢了就降窗) |
| 基于模型/测量 | BBR | 直接测带宽和 RTT,算出该发多快 |
二、CUBIC 的问题
CUBIC 的逻辑是「不停加速,直到丢包,再退回来」:
- 它把缓冲区填满才会丢包降速——这意味着链路上总是排着长队,延迟被拉高(Bufferbloat)。
- 它默认丢包 = 网络拥塞。但在无线、跨国、卫星等链路上,存在与拥塞无关的随机丢包,CUBIC 一遇到就大幅降窗,吞吐被反复砍,跑不满带宽。
三、BBR 的思路
BBR 不等丢包,而是持续测量两个量:
- BtlBw(瓶颈带宽):最近一段时间观测到的最大交付速率。
- RTprop(往返传播时延):最近一段时间观测到的最小 RTT(代表没有排队时的「纯路程」延迟)。
理想工作点:在途数据量 ≈ BtlBw × RTprop = BDP,发送速率 ≈ BtlBw。此时管道刚好填满、缓冲区几乎不排队——既跑满带宽又低延迟。
四、结果对比
| CUBIC | BBR | |
|---|---|---|
| 拥塞信号 | 丢包 | 测量带宽 + RTT |
| 有随机丢包时 | 吞吐骤降 | 基本不受影响 |
| 缓冲区 | 填满(高延迟,Bufferbloat) | 不填满(低延迟) |
| 长肥管道吞吐 | 一般 | 明显更高 |
完整版教学
一、拥塞控制的本质:估计「网络能吃多少」
发送方看不到网络内部,只能通过反馈信号猜测网络的承受能力,动态调节拥塞窗口 cwnd(在途未确认数据的上限)。核心矛盾:
- 发太慢 → 带宽浪费。
- 发太快 → 路由器缓冲区排队 → 延迟涨 → 溢出丢包 → 触发重传,更糟。
不同算法的根本区别在于:用什么信号来判断「是不是发太快了」。
二、基于丢包的 CUBIC:把丢包当刹车
CUBIC(Linux 长期默认)和更老的 Reno 都属于基于丢包的算法:
慢启动/拥塞避免:不断增大 cwnd(越发越快)
→ 直到丢包(认为网络满了)
→ 大幅降低 cwnd
→ 再慢慢涨回去
CUBIC 用一个三次函数让 cwnd 的增长更平滑、在高 BDP 下涨得更快,但判断拥塞的依据仍是丢包。这带来两个根本缺陷:
缺陷①:必须把缓冲区填满才知道该降速 → Bufferbloat
CUBIC 靠「丢包」感知拥塞,而丢包只有在路由器缓冲区被塞满、溢出时才发生。也就是说 CUBIC 会一直加速直到把中间缓冲区灌满。缓冲区里排着长队 → 每个包都要排队等待 → RTT 大幅升高。现代设备缓冲区又特别大,队列排得极长,延迟能涨好几倍——这就是 Bufferbloat(缓冲区膨胀)。结果:吞吐上去了,但延迟很差,交互体验糟糕。
缺陷②:把随机丢包误判成拥塞 → 吞吐上不去
CUBIC 假设「丢包 = 网络拥塞」。但很多链路存在与拥塞无关的丢包:
- 无线/移动网络的信号干扰。
- 跨国、卫星等长链路的偶发误码。
这些丢包不代表网络拥塞,但 CUBIC 一视同仁地大幅降 cwnd。在高 BDP 链路上,降下来再涨回去要很久,cwnd 长期远低于 BDP,带宽严重浪费。这正是「明明带宽很大、却跑不满」的常见元凶。
三、BBR:直接测量,绕开丢包这个坏信号
BBR 换了个根本思路:不猜,直接测量链路的两个关键参数,算出该发多快。
它持续维护两个测量值:
- BtlBw(Bottleneck Bandwidth,瓶颈带宽):一段时间窗口内观测到的最大交付速率(delivery rate)。这代表链路瓶颈的真实带宽。
- RTprop(Round-Trip Propagation time,往返传播时延):一段时间内观测到的最小 RTT。为什么取最小?因为排队会让 RTT 变大,只有没排队时测到的 RTT 才反映「纯路程延迟」。
BBR 的目标工作点(对应网络的最优状态):
在途数据量目标 ≈ BtlBw × RTprop = BDP
发送速率 ≈ BtlBw(配一个增益 pacing)
含义:让在途数据刚好填满管道(BDP),但不往缓冲区里堆。这样:
- 跑满带宽:发送速率贴着瓶颈带宽。
- 低延迟:不把缓冲区填满,几乎不排队,RTT 接近 RTprop。
- 抗随机丢包:丢几个包不影响它对带宽/RTT 的测量,不会因随机丢包无谓降速。
四、BBR 怎么持续校准:几个状态阶段
BtlBw 和 RTprop 会变(路况在变),BBR 用几个阶段轮换来持续探测:
- Startup(启动):类似慢启动,指数级加速,快速探到接近瓶颈带宽。
- Drain(排空):Startup 可能超发、在缓冲区堆了点数据,这一步降速把队列排空。
- ProbeBW(带宽探测):稳态主要阶段。周期性地稍微提速探测「带宽是不是变大了」,再降速把多发的排空,从而不断校准 BtlBw,同时保持队列很浅。
- ProbeRTT(RTT 探测):隔一段时间大幅减少在途数据,制造一个「没有排队」的时刻,重新测到真实的最小 RTT(RTprop),防止 RTprop 被长期高估。
通过这套轮换,BBR 在「跑满带宽」和「保持低延迟」之间动态平衡。
五、BBR 的适用场景与争议
明显收益场景:
- 长肥管道(高带宽 + 高延迟):跨国、跨区域专线。
- 有随机丢包的链路:无线、移动、卫星。
- 典型如 CDN 回源、跨国视频/下载、Google 自家服务,BBR 能显著提升吞吐、降低延迟。
争议与代价(答全面才加分):
- 公平性:BBR 和 CUBIC 共享同一瓶颈时,早期 BBR(v1)在某些场景会挤占 CUBIC 流的带宽,对丢包型算法不够友好(后续 BBRv2/v3 在改进公平性和对丢包的响应)。
- 浅缓冲区下可能引入丢包:BBR 主动探测带宽时可能在小缓冲区设备上造成额外丢包。
- 不是所有场景都更好:在缓冲区合理、丢包主要反映真实拥塞的稳定链路上,CUBIC 也工作得不错。
六、怎么用(Linux)
# 查看当前拥塞控制算法
sysctl net.ipv4.tcp_congestion_control
# 启用 BBR(需要内核支持,4.9+)
sysctl -w net.ipv4.tcp_congestion_control=bbr
# 配合公平队列 pacing 更佳
sysctl -w net.core.default_qdisc=fq
BBR 依赖发送速率 pacing(均匀发送),通常配合 fq 队列规则效果最好。
七、常见误区与追问
| 考点 | 正确口径 |
|---|---|
| 传统拥塞控制 | 多以丢包作为拥塞信号 |
| BBR | 估计瓶颈带宽和最小 RTT,控制发送速率 |
| 目标 | 尽量让链路跑满但不制造过多排队 |
BDP = bottleneck_bandwidth * min_RTT
if bandwidth = 100 Mbps, min_RTT = 40 ms
BDP = 100 * 10^6 / 8 * 0.04 = 500 KB
BBR 的思路是估计“管道容量”,而不是等丢包后再认定网络拥塞。
- 误区:BBR 完全不关心丢包。 BBR 不主要依赖丢包作为拥塞信号,但丢包仍会影响传输和实现策略。
- 误区:BBR 一定比 CUBIC 快。 BBR 在高带宽长 RTT、轻微随机丢包链路上常有优势,但公平性和队列表现要看场景。
- 误区:带宽估计越大越好。 估计过高会制造排队和丢包,BBR 需要周期性探测和收敛。
- 追问:BBR 为什么看 min RTT? 最小 RTT 近似表示无排队时传播时延,用来估计管道长度。
- 追问:BDP 有什么用? BDP 表示链路上“刚好填满管道”的在途数据量,是 pacing 和窗口控制的重要依据。
- 追问:BBR 适合解决什么痛点? 适合丢包不一定代表拥塞的链路,如无线、跨地域和高 BDP 网络。
八、加强记忆
BBR 是 Google 的 TCP 拥塞控制算法,思路是测量瓶颈带宽 BtlBw 和最小 RTT(RTprop),让在途数据 ≈ BtlBw × RTprop = BDP,从而跑满带宽又不把缓冲区填满。它对标的 CUBIC 是「基于丢包」 的,两大毛病:填满缓冲区才降速 → 高延迟(Bufferbloat),以及把随机丢包误判成拥塞 → 无谓降速、吞吐上不去。所以在高延迟 + 有随机丢包的链路(跨国、无线、CDN 回源)上 BBR 优势明显:更高吞吐、更低延迟、抗随机丢包。代价是公平性争议、浅缓冲区可能多丢包。核心一句:CUBIC 靠丢包踩刹车,BBR 靠测量踩油门。