TCP 拥塞控制核心机制:从慢启动到 BBR

举报
yd_210610071 发表于 2026/10/26 22:07:09 2026/10/26
【摘要】 TCP 拥塞控制核心机制:从慢启动到 BBR本文拆解 TCP 如何"猜"出可用带宽:经典四阶段算法的演进逻辑、丢包作为信号的局限,以及 BBR 为什么会把规则重写一遍。 为什么需要拥塞控制?没有拥塞控制的世界: 所有发送端都拼命往网络灌 → 路由器队列爆满 → 大面积丢包 → everyone 重传 → 更堵 → 拥塞崩溃(1986 年 Internet 就真实发生过全局吞吐骤降)T...

TCP 拥塞控制核心机制:从慢启动到 BBR

本文拆解 TCP 如何"猜"出可用带宽:经典四阶段算法的演进逻辑、丢包作为信号的局限,以及 BBR 为什么会把规则重写一遍。

为什么需要拥塞控制?

没有拥塞控制的世界:
  所有发送端都拼命往网络灌 → 路由器队列爆满 → 大面积丢包
  →  everyone 重传 → 更堵 → 拥塞崩溃(1986 年 Internet 就真实发生过全局吞吐骤降)

TCP 的任务:在"不知道链路容量"的前提下,自己试探出能跑多快,
           并且不比邻居贪心(公平性),也不把中间设备压垮。

两个约束合起来决定发送窗口:
  cwnd(拥塞窗口)—— 网络还能吃多少
  rwnd(接收窗口)—— 对方缓冲还剩多少
  实际发送量 = min(cwnd, rwnd)

经典四阶段(Reno 视角)

      0                                          带宽上限
  发送速率 ↑            拥塞避免(加法增)/\/\/\ 丢包
                      /
                    /
          指数增 ↑ /
      慢启动  / ↗(到 ssthresh 转折)
             /
            └──────────────────────────────▶ 时间
                     超时丢包 → 慢启动从头再来

1. 慢启动(Slow Start)
   cwnd 从初始值(通常 10 MSS / ~14KB)开始
   每收到一个 ACK → cwnd += 1 MSS → 每 RTT 翻倍(指数增长)
   不是"慢慢传",而是"先小步快探",因为不知道链路能扛多少

2. 拥塞避免(Congestion Avoidance)
   cwnd ≥ ssthresh 后:每 RTT 只 +1 MSS(加法增)
   指数→线性的转折目的:逼近容量时放慢试探速度

3. 快速重传(Fast Retransmit)
   收到 3 个重复 ACK → 不等超时立刻重传丢的那段
   (3 个 dupACK 说明后面的包都到了,只是中间掉了一个)

4. 快速恢复(Fast Recovery)
   丢包后 cwnd 减半、ssthresh = cwnd/2,从一半继续线性增
   Reno:超时则 cwnd 打回 1 重新慢启动(代价极狠)

核心哲学:AIMD(加法增、乘法减)——线性增长保证公平收敛,
乘性下降保证大家"一起退让",这是 Reno/CUBIC 家族的公共底座。

队列视角:Bufferbloat 与丢包信号

经典算法把"丢包"当网络拥塞的唯一信号,但现代网络有两个干扰项:

1. 随机丢包(无线误码、光路抖动)
   → 算法误判为拥塞,无谓降速

2. 缓冲膨胀(Bufferbloat)
   路由器队列很深:不丢包,但 RTT 从 10ms 涨到 300ms
   → cwnd 一路飙,延迟爆炸,吞吐反而变差(视频通话卡死的主因)

问题本质:靠"等爆队"来探测带宽 = 用高延迟换吞吐
于是出现两条改良路线:
  A. 更早、更细地看拥塞征兆(ECN、延迟梯度)
  B. 直接建模测带宽(BBR)

各算法一览

算法 关键改进 问题/定位
Tahoe 超时回到慢启动起点 太保守
Reno 3 dupACK → 快速重传/恢复 超时惩罚重;高带宽长链路吃不满
Vegas 用 RTT 差值预判拥塞(而非等丢包) 与 Reno 共存时吃亏(退让过早),未普及
NewReno 一个 RTT 内多段丢失的恢复修正 Linux 默认家族基础
CUBIC cwnd 按三次函数增长,靠 W_max 记忆探针 与 RTT 无关,高带宽友好;Linux 默认
Copa 以"延迟梯度"判断自己在瓶颈队列的哪一侧 公平性博弈强,研究热点
BBR 估计带宽×RTprop,主动不填队列 见下文

CUBIC 直觉

丢包后从 W_max 按 cubic 曲线回升:
  离 W_max 远 → 增得快(快速恢复)
  接近 W_max → 平台期微增(探测是否还能更高)
  超过后 → 缓慢回落稳定
好处:增长节奏与 RTT 解耦(长肥管道不再吃亏),
      高带宽下吞吐恢复极快,因此成为 Linux 默认。

BBR:把"猜丢包"换成"量带宽"

BBR(Google,2016;BBRv2 2019 改公平性)不再等丢包,而是持续估计两个物理量:

BtlBw  = 链路瓶颈带宽(近几个 RTT 交付速率的最大值)
RTprop = 最小往返时延(近 200s 内 RTT 最小值,≈ 纯传播延迟)

目标:发送量 = BDP = BtlBw × RTprop
      在"刚好填满管道、不填队列"的点全速跑

 pacing gain 控制每个时片的发送速率;
 cwnd 上限 = BDP × 2(只防超大队列)

状态机

START      慢启动(用 2.88 的高增益快速拉满,按丢包或
             "增长<2%"判据退出,而非等队满丢包)
  ↓
DRAIN      把慢启动灌多的排队清掉(gain 1/2.88),降到 RTT 回落
  ↓
PROBE_BW   稳态:以 1 倍带宽巡航,周期内一轮 gain=1.25 超发探测
           (4 个 RTT 维持 + 1 个 RTT 探测)
  ↓
PROBE_RTT  长期没看到更低的 RTT → 限时压到 4 个 packet 的极小量,
           排空队列重新量一次"干净" RTprop,然后回 PROBE_BW

BBR 的强项与争议

强项:
  - 有损/随机丢包链路(WiFi、跨洋)不再被误判降速
  - 低延迟下高吞吐(不把队列当缓存用)
  - 对 shallow buffer 友好,缓解 bufferbloat

争议(v1 为主):
  - 与丢包型算法共存时会"抢占"队列(公平性吃亏/占便宜双面)
  - 对整形器(token bucket 限速)可能测不满突发而低估带宽
  - 与 ECN/QoS 设备行为交互有坑
v2 改进:降 gain 1.25→1.13、对 ECN 标记更敏感、引入损失上限与
         主动 fairness 信号,收敛更接近传统算法。

工程落地备忘

# Linux 启用
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq        # 必须 fq/fq_codel(pacing 靠它)
ss -ti -p                          # 观察 delivery rate / rtt_min
常见误区:只开 bbr 不配 fq;容器里 sysctl 没生效;
        短连接场景收益有限(还没到 PROBE_BW 就结束了)

实战:怎么判断该用哪种

链路特征 推荐 理由
数据中心内网、浅队列 CUBIC / DCQCN 丢包率极低,传统算法表现稳定
跨洋/高 RTT 大文件 BBR 或 CUBIC+large init window 慢启动窗口与带宽探测都关键
移动网络、随机丢包 BBRv2 不把误码当拥塞
音视频实时通话 BBR/GCC(RTP 层的拥塞控制) 延迟优先于吞吐
CDN 静态分发 BBR 普及中 长尾链路质量参差

总结

维度 经典派(Reno/CUBIC) BBR
拥塞信号 丢包(队满的代理指标) 带宽/时延实测
控制目标 填满队列且不溢出 填满管道且不填队列
队列长度 天然偏深 偏浅、低延迟
公平性 AIMD 自收敛 v1 吃亏点,v2 补丁
部署现实 Linux 默认 CUBIC 云厂商/CDN 逐步铺

理解 TCP 拥塞控制的关键在于:传统算法是"以丢包为唯一反馈的分布式猜测游戏",优点是简单公平、缺点是拿延迟和队列当筹码;BBR 换了范式——把网络当可测量的物理系统,用交付速率和最小 RTT 建模出 BDP 并贴着上限跑,代价是需要 fq 这类精准 pacing 与更复杂的公平性补丁。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。