目录
正在加载目录…
专栏文章
专栏文章
网络算法系列
1. 轮询与加权轮询 2. 最小连接数 3. Jump Consistent Hash 4. Rendezvous Hashing 5. TCP 拥塞控制(CUBIC 与 BBR) 6. QUIC 丢包恢复与拥塞控制 7. 经典一致性哈希(虚拟节点) 8. P2C(Power of Two Choices) 9. TCP 滑动窗口与流量控制 10. Maglev Hashing

TCP 拥塞控制(CUBIC 与 BBR)

发布于 2026-06-04 04:44 · 最后编辑于 2026-07-31 15:54 · 字数 3,360 👁 104 次阅读

TCP 拥塞控制解决发送方如何感知网络容量、在不造成拥塞的前提下最大化吞吐的问题,CUBIC 是 Linux 默认算法,BBR 是 Google 2016 年提出的基于带宽探测的新一代算法。

相关文章Rendezvous Hashing · QUIC 丢包恢复与拥塞控制

tcp congestion

目录

章节说明
问题背景为什么需要拥塞控制,核心矛盾是什么
基础概念cwnd、rwnd、ssthresh、RTT 精确定义
经典 TCP Reno四阶段完整伪代码与执行追踪
CUBIC 算法三次函数增长模型,Linux 默认实现
BBR 算法基于带宽探测的主动感知,四状态机
BBR 状态机执行追踪从 STARTUP 到 PROBE_BW 的具体数值演示
CUBIC vs BBR 核心差异设计哲学、适用场景、公平性对比
异常与边界场景带宽突变、RTT 突变、多流竞争、ECN
参考资料论文、RFC、内核文档

问题背景

核心矛盾

TCP 发送方不知道路径上瓶颈链路的带宽,只能通过试探来学习:

  • 发送太慢:带宽利用率低,吞吐浪费
  • 发送太快:路由器队列溢出,分组丢失,触发重传,进一步加剧拥塞(拥塞崩溃)

1986 年 Van Jacobson 观察到 ARPANET 上吞吐量从 32 Kbps 骤降至 40 bps 的"拥塞崩溃"现象,随后在 RFC 1122/1323 中提出了慢启动与拥塞避免机制。

网络模型假设

发送方 ──── 路径(瓶颈链路 BtlBw)──── 接收方
            └── 路由器队列(Buffer)
  • 可用带宽 = 瓶颈链路带宽(BtlBw)
  • 传播延迟 = 路径最小 RTT(RTprop)
  • 队列延迟 = 额外增加的往返时延

基础概念

变量全称维护方含义
cwndCongestion Window发送方发送方允许在途(未确认)的最大字节数,单位 MSS 或字节
rwndReceiver Window接收方通告接收方缓冲区剩余空间,通过 TCP 头部 Window 字段传递
ssthreshSlow Start Threshold发送方区分慢启动与拥塞避免阶段的阈值,初始值通常为 64 KB
RTTRound-Trip Time发送方测量一个数据段从发出到收到 ACK 的时间,用于计算 RTO
MSSMaximum Segment Size协商单个 TCP 段最大数据字节数,通常 1460 字节(以太网)
BDPBandwidth-Delay Product计算值BtlBw × RTprop,充满管道所需字节数

实际发送窗口send_window = min(cwnd, rwnd)

经典 TCP Reno

3.1 四个阶段

阶段一:慢启动(Slow Start)

触发条件:连接建立初期,或超时重传后(cwnd 重置为 1 MSS)

// 慢启动:每收到一个 ACK,cwnd 增加 1 MSS → 每 RTT 翻倍(指数增长)
初始化:
    cwnd    = 1 MSS        // 初始拥塞窗口
    ssthresh = 64 KB       // 初始慢启动阈值(实现相关,RFC 建议更大)

on_ack_received(acked_bytes):
    if cwnd < ssthresh:
        cwnd += MSS                        // 慢启动:每 ACK 增加 1 MSS
        // 效果:每 RTT 内发 cwnd/MSS 个包,收到 cwnd/MSS 个 ACK
        //       cwnd += cwnd,即每 RTT 翻倍
    else:
        cwnd += MSS * MSS / cwnd           // 拥塞避免:每 RTT 增加约 1 MSS
        // 公式推导:每个 ACK 增加 MSS²/cwnd,
        //           一个 RTT 内有 cwnd/MSS 个 ACK,
        //           总增加 = (cwnd/MSS) * (MSS²/cwnd) = MSS

阶段二:拥塞避免(Congestion Avoidance)

触发条件:cwnd >= ssthresh

on_ack_received(acked_bytes):
    if cwnd >= ssthresh:
        cwnd += MSS * MSS / cwnd           // 每 RTT 线性增加 1 MSS

阶段三:快速重传(Fast Retransmit)

触发条件:收到 3 个重复 ACK(dup ACK),说明某段丢失但后续段到达

// 重复 ACK 计数器
dup_ack_count = 0

on_ack_received(ack_seq):
    if ack_seq == last_ack_seq:            // 收到重复 ACK
        dup_ack_count += 1
        if dup_ack_count == 3:             // 三次重复 ACK → 快速重传
            retransmit(last_ack_seq)       // 立即重传丢失段,不等超时
            ssthresh = max(cwnd / 2, 2 * MSS)   // 阈值减半
            cwnd     = ssthresh            // 窗口设为新阈值(进入快速恢复)
            dup_ack_count = 0
    else:
        dup_ack_count = 0                  // 收到新 ACK,重置计数
        // 正常 ACK 处理(慢启动或拥塞避免)

阶段四:快速恢复(Fast Recovery)

触发条件:快速重传后,从 ssthresh 继续拥塞避免(不回到慢启动)

// 快速恢复:cwnd 已设为 ssthresh,直接进入拥塞避免阶段
// 区别于超时:超时后 cwnd 重置为 1 MSS,从慢启动重新开始
on_timeout():
    ssthresh = max(cwnd / 2, 2 * MSS)
    cwnd     = 1 * MSS                    // 超时:重置为 1,重新慢启动
    dup_ack_count = 0

3.2 执行追踪(Reno,MSS=1,ssthresh=8)

RTT  事件              cwnd   ssthresh  说明
---  ---------------  -----  --------  --------------------------
0    连接建立           1      8         初始状态
1    1个ACK            2      8         慢启动,翻倍
2    2个ACK            4      8         慢启动,翻倍
3    4个ACK            8      8         cwnd==ssthresh,进入拥塞避免
4    8个ACK            9      8         线性+1
5    9个ACK            10     8         线性+1
6    收到3个dup ACK     5      5         ssthresh=10/2=5, cwnd=5
7    从ssthresh继续     6      5         拥塞避免,线性+1

3.3 TCP Reno 的局限性

  • 高 BDP 网络:BDP = 100 Mbps × 100ms = 1.25 MB,线性增长需要数百 RTT 才能充满管道
  • RTT 不公平:RTT 小的流每秒能做更多次 AIMD 循环,获得更多带宽
  • 丢包≠拥塞:无线网络随机丢包也会触发窗口减半

CUBIC 算法

4.1 问题背景

Linux 2.6.19(2006年)将默认拥塞控制从 BIC 改为 CUBIC。核心改进:用三次函数替代线性增长,在高 BDP 网络中快速恢复到历史最大窗口。

4.2 核心数据结构

struct cubic_state {
    u32 W_max;        // 上次丢包时的 cwnd(历史最大窗口,单位 MSS)
    u32 W_last_max;   // 上上次丢包时的 W_max,用于快速收敛
    u32 K;            // cwnd 增长达到 W_max 的时间点(秒)
    u32 t_epoch;      // 上次丢包/窗口减小的时间戳(秒)
    u32 cwnd;         // 当前拥塞窗口(MSS)
    u32 ssthresh;     // 慢启动阈值
    // 常数
    // C = 0.4(CUBIC 缩放因子,控制增长速度)
    // beta = 0.7(乘性减少因子,比 Reno 的 0.5 更保守)
};

4.3 三次函数增长模型

W_cubic(t) = C * (t - K)³ + W_max

其中:
  t = 当前时间 - t_epoch(距上次丢包的时间,秒)
  K = ∛(W_max * (1 - beta) / C)
    = ∛(W_max * 0.3 / 0.4)
  C = 0.4(论文推荐值)
  beta = 0.7(乘性减少因子)

函数特性:
  t=0 时:W_cubic(0) = C*(0-K)³ + W_max = -C*K³ + W_max = W_max*(1-beta) = 0.7*W_max
  t=K 时:W_cubic(K) = 0 + W_max(恢复到丢包前水平)
  t>K 时:超过 W_max,继续探测更高带宽

4.4 完整伪代码

// CUBIC 初始化
cubic_init():
    W_max    = 0
    K        = 0
    t_epoch  = 0
    cwnd     = 1 * MSS
    ssthresh = INITIAL_SSTHRESH    // 通常 64KB / MSS

// 收到 ACK 时更新 cwnd
cubic_on_ack(now):
    if cwnd < ssthresh:
        cwnd += MSS                // 慢启动阶段,指数增长
        return

    t = now - t_epoch              // 距上次丢包的时间(秒)

    // 计算 CUBIC 目标窗口
    W_cubic_t = C * (t - K)^3 + W_max    // C=0.4

    // 与 TCP 友好性(Reno 等效窗口)比较,取较大值
    // Reno 等效:W_est += MSS * (3*beta/(2-beta)) / cwnd * per_ack
    // 实现上简化为:W_est = W_max * beta + 3*(1-beta)/(1+beta) * t/RTT
    W_tcp_friendly = W_est(t)

    target = max(W_cubic_t, W_tcp_friendly)

    if target > cwnd:
        cwnd += (target - cwnd) / cwnd    // 每 ACK 增量,分摊到一个 cwnd
    else:
        cwnd unchanged                     // 不减少

// 检测到丢包(3 个 dup ACK)
cubic_on_loss():
    W_last_max = W_max
    W_max      = cwnd              // 记录丢包时窗口

    // 快速收敛:如果本次 W_max 小于上次,说明带宽减少,更快收缩
    if W_max < W_last_max:
        W_max = W_max * (2 - beta) / 2    // W_max = W_max * 0.85

    ssthresh = max(cwnd * beta, 2 * MSS)   // ssthresh = 0.7 * cwnd
    cwnd     = ssthresh

    // 重新计算 K,t_epoch 重置
    K       = cbrt(W_max * (1 - beta) / C)
    t_epoch = now

// 超时
cubic_on_timeout():
    W_max    = cwnd
    ssthresh = max(cwnd * beta, 2 * MSS)
    cwnd     = 1 * MSS            // 回到慢启动
    K        = cbrt(W_max * (1 - beta) / C)
    t_epoch  = now

4.5 执行追踪(CUBIC,W_max=20,beta=0.7,C=0.4,MSS=1)

事件           t(s)   K(s)   cwnd   ssthresh  W_cubic(t)  说明
-----------   -----  -----  -----  --------  ----------  -------------------
丢包发生       0      2.94   20     14        14.0        K=∛(20*0.3/0.4)≈2.94
               0.5    2.94   14     14        14.0-1.27≈12.7 → 保持14(min)
               1.0    2.94   14     14        ≈13.4       W_cubic=0.4*(1-2.94)³+20≈13.4
               1.5    2.94   15     14        ≈15.9       超过cwnd,增长
               2.0    2.94   16     14        ≈18.3       接近W_max,加速
               2.94   2.94   20     14        20.0        恢复到W_max
               3.5    2.94   21     14        21.3        超过W_max,继续探测
新丢包         3.5    ←      21→14  14        重置         W_max=21, K重新计算

CUBIC vs Reno 增长速度对比(相同 W_max=20,t=2s 时):

  • Reno:每 RTT +1,从 14 到 20 需要 6 个 RTT
  • CUBIC:t=2s 时 W_cubic≈18.3,仅需约 3s(假设 RTT=200ms 即 15 个 RTT 内完成)

BBR 算法

5.1 设计哲学:从丢包感知到带宽感知

传统算法(Reno/CUBIC):
  感知信号 = 丢包(被动等待队列溢出)
  问题:
    ① 浅队列路由器:少量数据就丢包,带宽利用率低
    ② 无线链路随机丢包:误触发窗口减半
    ③ 高 BDP 链路:恢复太慢

BBR(Bottleneck Bandwidth and RTT):
  感知信号 = 带宽(BtlBw)+ 最小 RTT(RTprop)
  目标:以瓶颈带宽发送,不在队列中积压数据(工作在 BDP 点)

5.2 核心数据结构

struct bbr_state {
    // 带宽估算(滑动窗口最大值)
    u64  btlbw;          // 瓶颈带宽估算(bps),= delivered / interval
    u64  btlbw_filter;   // 10 RTT 内的最大带宽(WindowedMaxFilter)

    // RTT 估算
    u32  rtprop;         // 最小 RTT(ns),= min(RTT) over last 10s
    u64  rtprop_stamp;   // rtprop 最后更新时间

    // 发送速率控制
    u64  pacing_rate;    // 实际发送速率 = btlbw * pacing_gain
    u32  cwnd;           // 拥塞窗口 = btlbw * rtprop * cwnd_gain
    
    // 状态机
    enum bbr_mode mode;  // STARTUP / DRAIN / PROBE_BW / PROBE_RTT
    u32  pacing_gain;    // 发送速率增益(定点数,1.0=2048)
    u32  cwnd_gain;      // 窗口增益

    // PROBE_BW 轮转
    u8   cycle_idx;      // pacing_gain 周期索引(0-7)
    u64  cycle_stamp;    // 当前 pacing_gain 阶段开始时间

    // 统计
    u64  delivered;      // 累计已确认交付字节数
    u64  delivered_stamp;// delivered 上次记录时间
};

// pacing_gain 周期(PROBE_BW 状态,8个相位)
// 相位0: 1.25 → 探测更高带宽
// 相位1: 0.75 → 排空多余队列
// 相位2-7: 1.0  → 稳定巡航
pacing_gain_cycle[8] = {1.25, 0.75, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}

5.3 四个状态

状态目标pacing_gaincwnd_gain退出条件
STARTUP指数探测最大带宽2.8852.885btlbw 连续 3 轮无增长
DRAIN排空 STARTUP 积压队列1/2.885≈0.352.885in_flight ≤ BDP
PROBE_BW周期性探测带宽,稳态运行轮转[1.25,0.75,1.0×6]2PROBE_RTT 触发
PROBE_RTT降低 cwnd 测量最小 RTT当前值1持续 200ms 后恢复

5.4 完整伪代码

// BBR 初始化
bbr_init():
    mode          = STARTUP
    pacing_gain   = 2.885        // ≈ 2/ln2,指数增长
    cwnd_gain     = 2.885
    btlbw         = 0
    rtprop        = +∞
    rtprop_stamp  = now()
    cycle_idx     = 0
    delivered     = 0

// 每个 ACK 到达时调用
bbr_on_ack(rtt, delivered_delta, interval):
    // 1. 更新带宽估算
    bw_sample = delivered_delta / interval        // 采样带宽
    btlbw = WindowedMax(btlbw_filter, bw_sample, 10 * rtprop)  // 10 RTT 窗口最大值

    // 2. 更新最小 RTT
    if rtt < rtprop:
        rtprop       = rtt
        rtprop_stamp = now()

    // 3. 状态机转换
    bbr_update_mode()

    // 4. 更新发送参数
    pacing_rate = btlbw * pacing_gain
    cwnd        = max(btlbw * rtprop * cwnd_gain, 4 * MSS)  // 不低于4MSS

// 状态机转换逻辑
bbr_update_mode():
    switch mode:
        case STARTUP:
            if btlbw_no_growth_for(3_rounds):    // 连续3轮带宽不增长
                mode        = DRAIN
                pacing_gain = 1.0 / 2.885        // ≈ 0.35,快速排空
                cwnd_gain   = 2.885

        case DRAIN:
            in_flight = packets_in_flight * MSS
            if in_flight <= btlbw * rtprop:      // 队列已排空
                mode        = PROBE_BW
                cycle_idx   = 0
                pacing_gain = pacing_gain_cycle[0]  // 1.25
                cwnd_gain   = 2.0
                cycle_stamp = now()

        case PROBE_BW:
            // 每个 RTT 推进一个 pacing_gain 相位
            if now() - cycle_stamp >= rtprop:
                cycle_idx   = (cycle_idx + 1) % 8
                pacing_gain = pacing_gain_cycle[cycle_idx]
                cycle_stamp = now()
            // 检查是否需要 PROBE_RTT
            if now() - rtprop_stamp >= 10s:       // 10s 未更新最小 RTT
                mode        = PROBE_RTT
                cwnd_gain   = 1.0

        case PROBE_RTT:
            cwnd = max(4 * MSS, ...)               // 降低 cwnd
            if probe_rtt_done():                   // 持续200ms且in_flight≤4MSS
                rtprop_stamp = now()               // 重置计时器
                mode         = STARTUP if not_filled_pipe else PROBE_BW
                restore_cwnd_gain()

// BBR 对丢包的处理(不触发窗口减半)
bbr_on_loss():
    // BBR 不把丢包作为拥塞信号
    // 但遵守 TCP 重传机制(快速重传、超时重传)
    // cwnd 短暂设为 in_flight(保守),不做乘性减少
    cwnd = min(cwnd, in_flight)    // 不减半,仅保守处理

5.5 带宽测量细节

// 带宽采样(每个 ACK)
on_ack(ack):
    now_delivered  = total_delivered         // 当前累计交付
    now_time       = now()

    // 记录该数据包发出时的状态
    bw_sample = (now_delivered - pkt.delivered) /
                (now_time      - pkt.delivered_time)

    // 使用 Windowed Max Filter(滑动窗口最大值)
    // 窗口大小 = 10 RTT,保留近期最大带宽
    btlbw = WindowedMax(btlbw, bw_sample, window=10*rtprop)

BBR 状态机执行追踪

场景:100 Mbps 链路,RTprop=20ms,从 STARTUP 开始

时间(ms)  状态       btlbw(Mbps)  rtprop(ms)  cwnd(KB)  pacing_rate(Mbps)  事件
------   -------    -----------  ----------  --------  -----------------  ----
0        STARTUP    0            +∞          4MSS      0                  初始化
20       STARTUP    12           20          ~10       34.6               第1轮ACK,btlbw=12
40       STARTUP    25           20          ~20       72.1               第2轮,btlbw增长
60       STARTUP    50           20          ~40       144.3              第3轮,翻倍
80       STARTUP    100          20          ~80       288.5              接近瓶颈
100      STARTUP    100          20          ~80       288.5              btlbw无增长第1轮
120      STARTUP    100          20          ~80       288.5              btlbw无增长第2轮
140      STARTUP    100          20          ~80       288.5              btlbw无增长第3轮→转DRAIN
140      DRAIN      100          20          ~80       35.0               pacing_gain=0.35
160      DRAIN      100          20          ~50       35.0               排空队列中
180      DRAIN      100          20          25(=BDP)  35.0               in_flight≤BDP→转PROBE_BW
180      PROBE_BW   100          20          50        125.0              phase0: gain=1.25
200      PROBE_BW   100          20          50        75.0               phase1: gain=0.75,排空
220      PROBE_BW   100          20          50        100.0              phase2-7: gain=1.0,稳态
...
10000    PROBE_RTT  100          20          4MSS      100.0              10s未更新rtprop→降cwnd
10200    PROBE_BW   100          20          50        100.0              200ms测量完成,恢复

// BDP 计算:100Mbps × 20ms = 2.5MB → cwnd ≈ 2.5MB × 2(cwnd_gain) = 5MB
// 实际 cwnd(KB) = 100*1000000/8 * 0.020 * 2 / 1024 ≈ 488 KB(图中简化为50KB演示)

PROBE_BW 一轮 pacing_gain 周期(稳态,btlbw=100Mbps,RTprop=20ms)

相位  持续(ms)  pacing_gain  pacing_rate(Mbps)  效果
----  --------  -----------  -----------------  ------------------
0     20        1.25         125                超速发送,探测带宽上界
1     20        0.75         75                 降速,排空phase0积压
2     20        1.0          100                稳定
3     20        1.0          100                稳定
4     20        1.0          100                稳定
5     20        1.0          100                稳定
6     20        1.0          100                稳定
7     20        1.0          100                稳定(周期结束)
// 每个相位持续约 1 RTT(20ms),完整周期 = 8 RTT = 160ms
// 如果phase0探测到更高带宽,btlbw更新,后续稳态速率提升

CUBIC vs BBR 核心差异

7.1 设计哲学对比

维度CUBICBBR
拥塞信号丢包(被动,队列溢出后感知)带宽+RTT(主动探测,不等丢包)
工作点满队列(高吞吐但高延迟)BDP 点(平衡吞吐与延迟)
丢包响应窗口减少到 0.7×cwnd不减窗口(不视丢包为拥塞信号)
RTT 公平性较差(短 RTT 流占优)较好(基于带宽不受 RTT 影响)
高 BDP 网络恢复慢(三次函数改善)快速充满管道(STARTUP 指数探测)
低延迟要求会在队列中积压数据主动控制队列,延迟更低
浅队列路由器适应性好(丢包就减速)可能加剧丢包(不响应丢包)
与 CUBIC 竞争公平BBR 可能占用更多带宽

7.2 适用场景

CUBIC 更适合

  • 数据中心内部(短 RTT,浅队列,CUBIC 流之间公平)
  • 与大量 CUBIC 客户端混合的环境
  • AQM(主动队列管理,如 FQ-CoDel)未部署的网络

BBR 更适合

  • 高 BDP 链路(跨洋、卫星,RTT 100ms+)
  • 无线网络(随机丢包不应触发拥塞响应)
  • 需要低延迟的场景(视频会议、游戏)
  • Google 内部网络、YouTube CDN

7.3 BBR 的已知问题

问题1:浅队列公平性
  现象:BBR 流与 CUBIC 流竞争时,BBR 可能获取不成比例的带宽
  原因:CUBIC 丢包就减速,BBR 不减速,导致 CUBIC 流被"饿死"
  缓解:部署 FQ(公平队列)调度器,per-flow 限速

问题2:RTT 膨胀
  BBR v1:PROBE_RTT 期间 cwnd 降至 4MSS,可能导致短暂吞吐下降
  BBR v2:改进 PROBE_RTT,减少影响

问题3:多流竞争不公平
  同一瓶颈上多条 BBR 流:btlbw 各自独立估算,可能过于乐观
  BBR v2:引入丢包信号辅助限速(L_target=2%),改善公平性

异常与边界场景

场景一:带宽突然增加(扩容或路由切换)

初始状态:btlbw=100Mbps,PROBE_BW 稳态运行

带宽变化:路径切换,瓶颈带宽从 100Mbps → 200Mbps

BBR 的处理:
  t=0:    pacing_rate = 100Mbps(旧 btlbw)
  t=RTT:  phase0 以 1.25×100=125Mbps 探测
          实际吞吐=125Mbps(新带宽充足,无队列积压)
          新 bw_sample = 125Mbps → btlbw 更新为 125Mbps
  t=2RTT: phase0 再次以 1.25×125=156Mbps 探测
          bw_sample ≈ 156Mbps → btlbw=156Mbps
  t=N×RTT: 通过 PROBE_BW 周期性探测,btlbw 逐渐逼近 200Mbps
  
  收敛时间:约 log₁.₂₅(200/100) = 3.1 个探测相位 ≈ 3 RTT
  特点:无需丢包,主动感知带宽增长

场景二:RTT 突然增加(路由变化或网络抖动)

初始状态:rtprop=20ms,PROBE_BW 稳态

RTT 变化:拥塞或路由切换,RTT 从 20ms → 50ms

BBR 的处理:
  t=0:    rtprop=20ms(最小 RTT 记录)
          当前 RTT=50ms > rtprop,不更新 rtprop
          cwnd = btlbw × rtprop × cwnd_gain(用旧 rtprop)
          pacing_rate = btlbw × pacing_gain(不变)
  
  问题:cwnd 基于旧 rtprop(20ms),实际 RTT=50ms
        in_flight 可能超过 cwnd → 等效于窗口不足,吞吐下降约 60%
  
  10s后:触发 PROBE_RTT(10s 未更新 rtprop)
  PROBE_RTT 阶段:
    cwnd = 4 MSS(极小值)
    持续 200ms 测量 RTT
    如果 RTT 真的是 50ms(稳定的新 RTprop)→ rtprop=50ms 更新
    如果 RTT 降回 20ms(临时抖动)→ rtprop 仍=20ms,不更新
  
  更新后:cwnd = btlbw × 50ms × 2 = 原来的 2.5 倍,吞吐恢复

场景三:多流竞争(BBR 流公平性)

场景:同一 100Mbps 瓶颈上,2 条 BBR 流(flow1, flow2)

理想情况:各占 50Mbps
实际问题:
  flow1 的 btlbw_filter 记录到 80Mbps(历史峰值)
  flow2 的 btlbw_filter 记录到 70Mbps
  两流共同 pacing_rate = 80+70 = 150Mbps > 100Mbps(链路满载)
  → 队列积压,RTT 增加,但 BBR 不减速(不响应丢包)

缓解措施:
  1. FQ 调度器(tc-fq):每流独立限速,防止单流垄断
  2. BBR v2:引入 inflight_lo 基于丢包率限制 in_flight
  3. ECN:网络设备标记拥塞,BBR v2 可响应 CE 标记

场景四:ECN 配合使用

ECN(Explicit Congestion Notification,RFC 3168):
  路由器在队列开始满时,给数据包打 CE(Congestion Experienced)标记
  接收方通过 ACK 中的 ECE 标志通知发送方
  发送方收到 ECE → 减速(类似丢包处理)

CUBIC + ECN:
  收到 ECE → ssthresh = cwnd * 0.7,cwnd = ssthresh
  效果:在丢包前提前减速,减少实际丢包率

BBR v1 + ECN:
  BBR v1 基本忽略 ECN(设计上不响应丢包/ECN)
  可能导致在部署 ECN 的网络中行为不友好

BBR v2 + ECN:
  BBR v2 响应 CE 标记,调整 pacing_rate 和 inflight_lo
  在 ECN 环境中与 CUBIC 更公平
  
配置(Linux):
  sysctl net.ipv4.tcp_ecn=1         # 启用 ECN
  sysctl net.ipv4.tcp_congestion_control=bbr  # 使用 BBR
  tc qdisc add dev eth0 root fq     # 部署 FQ 调度器

参考资料

论文

  1. CUBIC: Sangtae Ha, Injong Rhee, Lisong Xu. CUBIC: A New TCP-Friendly High-Speed TCP Variant. ACM SIGOPS Operating Systems Review, 2008.
  2. BBR v1: Neal Cardwell, Yuchung Cheng, C. Stephen Gunn, Soheil Hassas Yeganeh, Van Jacobson. BBR: Congestion-Based Congestion Control. ACM Queue, 2016.
  3. BBR v2: Neal Cardwell et al. BBRv2: A Model-Based Congestion Control. IETF TSVWG, 2019.
  4. 原始拥塞控制: Van Jacobson, Michael J. Karels. Congestion Avoidance and Control. ACM SIGCOMM, 1988.

RFC

  1. RFC 5681 — TCP Congestion Control(Reno 规范)
  2. RFC 3168 — The Addition of Explicit Congestion Notification (ECN) to IP
  3. RFC 6582 — The NewReno Modification to TCP's Fast Recovery Algorithm

代码与文档

  1. Linux 内核 CUBIC 实现:net/ipv4/tcp_cubic.c
  2. Linux 内核 BBR 实现:net/ipv4/tcp_bbr.c
  3. Google BBR 技术博客:https://cloud.google.com/blog/products/networking/tcp-bbr-congestion-control-comes-to-gcp-your-internet-just-got-faster

书籍

  1. Computer Networks: A Systems Approach, Peterson & Davie, Chapter 6
  2. TCP/IP Illustrated, Volume 1, W. Richard Stevens, Chapter 16
← 返回列表

评论 (0)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论