BBR与KCC发送速率调节机制
0. 问题界定
拥塞控制算法的核心输出只有两个变量:Pacing Rate(物理发送速率)和CWND(逻辑拥塞窗口)。本文通过源码和可视化图表,剖析 BBR 与 KCC 在决定"下一时刻该发多快"时的核心逻辑。
1. BBR的速率调节:增益表 + inflight门控
BBR 在PROBE_BW(稳态探测)阶段,速率调节依赖一个硬编码的 8 拍增益表(bbr_pacing_gain[] = {1.25, 0.75, 1,1,1,1,1,1})。它通过 inflight(在途字节数)判断是否超越物理 BDP,但不直接测量排队延迟。
1.1 BBR的增益控制流程
关键点:
- Probe(1.25x)需要同时满足"至少 1 个 min_rtt"和"丢包或 inflight 达标"方可退出
- Drain(0.75x)可通过
inflight ≤ BDP立即短路退出(||条件),无需等满 1 个 min_rtt - Cruise(1.0x)仅由时钟驱动,必须完成 1 个 min_rtt 才可切换至下一相位
1.2 BBR的数学本质:开环增益调度
BBR 不直接测量T_queue。它写死了 8 个固定增益,靠 inflight 门控探测与排空,辅以丢包/延迟后的被动 TCP 窗口回缩。这在控制论中被归类为开环(Open-loop)预测控制。
2. KCC的速率调节:排队测量驱动的闭环修正
KCC 将 BBR 的固定 8 拍增益表扩展为 256 槽位(KCC_GAIN_SLOTS = 256),每槽对应 1 个 RTT 时的增益。默认配置下,增益表结构为:phase 0 = 1.25x(探测),phase 1 = 0.75x(排空),phase 2~(cycle_len-1) = 1.0x(巡航),该模式按cycle_len(默认 = 8)在整个 256 槽表中重复。
KCC 引入卡尔曼滤波器实时估计 T_prop(传播延迟),从qdelay = max(0, RTT_obs − x_est_us)派生瞬时排队延迟,通过 EWMA(默认权重 7/8)平滑为qdelay_avg。速率调节由此变成了受排队测量驱动的自适应边界追踪。
2.1 KCC的线性增益衰减
KCC 在探测阶段不盲目执行 1.25x 增益,而是通过排队(qdelay)和抖动(jitter)两项线性且顺序衰减来计算最终增益。衰减仅作用于增益表相位大于 1.0x(BBR_UNIT)的相位:
关键点:
- 非二值开关,而是线性比例衰减:
r_q ∝ (qdelay_avg − T_cong),r_j ∝ (jitter − T_cong) - 顺序扣除而非求和:qdelay 先消耗预算
max_red,jitter 再消耗余量;两者各自独立 clamped 在可用预算内,不是min(∑, max_red) - 卡尔曼置信度缩放:当
p_est > converged_val(未收敛),conf_scale < BBR_UNIT,衰减效果打折——滤波器不确定时不去轻易压制探测增益 - 增益绝不会跌破 BBR_UNIT(1.0x),即排队再严重也不会把探测降穿到巡航水平
2.2 KCC的Drain-Skip机制
当 KCC 周期轮转到0.75x排空阶段时,可在条件满足时直接将排空转为巡航(“drain-skip”),避免无效的吞吐断崖:
与 BBR 的关键差异:
- BBR 排空使用OR-gate:
is_full_length || inflight ≤ BDP,inflight 达标即可立即退出 - KCC 排空使用AND-gate:
is_full_length && drained,必须同时满足"满 1 RTT"和"inflight ≤ BDP"才能退出(另加 4×min_rtt 安全超时),这是对 BBRv1 过早退出排空的修复 - KCC 的 drain-skip 在 AND-gate 之上提供了一条额外的提前退出路径:当卡尔曼收敛且排队低于清洁阈值时,绕开 AND-gate 直接将排空转为巡航
2.3 KCC 与 BBR 控制回路的本质差异
3. 辅助速率调节机制
3.1 PROBE_RTT 机制
两种算法都设有 PROBE_RTT 模式:以极低的 pacing_gain(~0.5x BDP)持续 200ms,强制清空缓冲以测量真实 min_rtt。
- BBR:每 10 秒固定触发一次,无论路径是否需要。这会产生周期性的吞吐量"断崖"。
- KCC:引入
kcc_probe_rtt_decouple(默认开启)——当卡尔曼滤波器健康(p_est ≤ recal_thresh)时,跳过不必要的 PROBE_RTT,仅在工作状态恶化时才触发。这消除了 BBR 的周期性吞吐断崖。
3.2 ECN 退避与 CWND 增益约束
KCC 在排队压力下同时从两个维度收缩:
- ECN 退避:
kcc_ecn_backoff()检测 ECN 标记后,通过factor = (1 − ECN_ratio) × BBR_UNIT降低cwnd_gain,逻辑上相当于在排队超出阈值时收窄拥塞窗口的上限 - CWND 排队约束:
kcc_apply_cwnd_constraints()在qdelay_avg超过拥塞阈值且不在 PROBE_BW 模式时,缩减cwnd_gain至更保守的水平
这两项机制确保 KCC 在 CWND 维度上同样对排队做出响应,而非仅依赖 pacing_gain。
3.3 算法对比总表
| 维度 | BBR(tcp_bbr.c) | KCC(tcp_kcc.c) |
|---|---|---|
| 增益表 | 固定 8 拍{1.25, 0.75, 1×6} | 默认 256 槽,pattern 重复(默认cycle_len=8匹配 BBR) |
| 探测衰减 (probe) | 不衰减,逼满执行 1.25x | qdelay/jitter线性衰减+ 卡尔曼置信度缩放,floor = 1.0x |
| 排空退出 (drain) | OR-gate:is_full_length || inflight ≤ BDP | AND-gate:is_full_length && drained+ 4 RTT 超时 |
| 排空跳跃 (drain-skip) | 无 | 卡尔曼收敛 + qdelay < clean_thresh + min_rtt/8 驻留 → 跳过排空 |
| PROBE_RTT | 每 10s 强制触发 | 卡尔曼健康时跳过,仅异常时触发 |
| ECN / CWND 约束 | 无 ECN 响应 | ECN 退避降低 cwnd_gain;qdelay 超标时同时压缩 cwnd_gain |
4. 结论
BBR 的速率调节是增益表 + inflight 门控:bbr_pacing_gain[]提供固定节拍,probe 盲目冲高 (+25%),drain 通过 inflight 短路退出,不直接感知排队深度。
KCC 将 BBR 的框架重构为三层叠加:
- 增益表扩展:从 8 拍固定数组到 256 槽可配置表,保留 BBR 兼容默认值
- 线性排队衰减:
gain = max(1.0, probe − conf·min(r_q, budget) − conf·min(r_j, budget)),qdelay 和 jitter 先后消耗预算,衰减受卡尔曼置信度比例缩放 - 卡尔曼收敛门控:drain-skip 在 AND-gate 排空之上增加提前跳跃路径;PROBE_RTT 在链路健康时可跳过;ECN/CWND 约束在 qdelay 超标时同步收窄
差异的本质:BBR 在固定节拍和 inflight 门控内寻找边界;KCC 在每个节拍上叠加排队测量的自适应修正——线性衰减(非二值)、顺序消耗预算(非求和)、置信度缩放(非全量门控)。