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的增益控制流程
#mermaid-svg-3aaIiVea7nkBzRAB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3aaIiVea7nkBzRAB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3aaIiVea7nkBzRAB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3aaIiVea7nkBzRAB .error-icon{fill:#552222;}#mermaid-svg-3aaIiVea7nkBzRAB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3aaIiVea7nkBzRAB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3aaIiVea7nkBzRAB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3aaIiVea7nkBzRAB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3aaIiVea7nkBzRAB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3aaIiVea7nkBzRAB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3aaIiVea7nkBzRAB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3aaIiVea7nkBzRAB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3aaIiVea7nkBzRAB .marker.cross{stroke:#333333;}#mermaid-svg-3aaIiVea7nkBzRAB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3aaIiVea7nkBzRAB p{margin:0;}#mermaid-svg-3aaIiVea7nkBzRAB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3aaIiVea7nkBzRAB .cluster-label text{fill:#333;}#mermaid-svg-3aaIiVea7nkBzRAB .cluster-label span{color:#333;}#mermaid-svg-3aaIiVea7nkBzRAB .cluster-label span p{background-color:transparent;}#mermaid-svg-3aaIiVea7nkBzRAB .label text,#mermaid-svg-3aaIiVea7nkBzRAB span{fill:#333;color:#333;}#mermaid-svg-3aaIiVea7nkBzRAB .node rect,#mermaid-svg-3aaIiVea7nkBzRAB .node circle,#mermaid-svg-3aaIiVea7nkBzRAB .node ellipse,#mermaid-svg-3aaIiVea7nkBzRAB .node polygon,#mermaid-svg-3aaIiVea7nkBzRAB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3aaIiVea7nkBzRAB .rough-node .label text,#mermaid-svg-3aaIiVea7nkBzRAB .node .label text,#mermaid-svg-3aaIiVea7nkBzRAB .image-shape .label,#mermaid-svg-3aaIiVea7nkBzRAB .icon-shape .label{text-anchor:middle;}#mermaid-svg-3aaIiVea7nkBzRAB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3aaIiVea7nkBzRAB .rough-node .label,#mermaid-svg-3aaIiVea7nkBzRAB .node .label,#mermaid-svg-3aaIiVea7nkBzRAB .image-shape .label,#mermaid-svg-3aaIiVea7nkBzRAB .icon-shape .label{text-align:center;}#mermaid-svg-3aaIiVea7nkBzRAB .node.clickable{cursor:pointer;}#mermaid-svg-3aaIiVea7nkBzRAB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3aaIiVea7nkBzRAB .arrowheadPath{fill:#333333;}#mermaid-svg-3aaIiVea7nkBzRAB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3aaIiVea7nkBzRAB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3aaIiVea7nkBzRAB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3aaIiVea7nkBzRAB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3aaIiVea7nkBzRAB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3aaIiVea7nkBzRAB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3aaIiVea7nkBzRAB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3aaIiVea7nkBzRAB .cluster text{fill:#333;}#mermaid-svg-3aaIiVea7nkBzRAB .cluster span{color:#333;}#mermaid-svg-3aaIiVea7nkBzRAB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3aaIiVea7nkBzRAB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3aaIiVea7nkBzRAB rect.text{fill:none;stroke-width:0;}#mermaid-svg-3aaIiVea7nkBzRAB .icon-shape,#mermaid-svg-3aaIiVea7nkBzRAB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3aaIiVea7nkBzRAB .icon-shape p,#mermaid-svg-3aaIiVea7nkBzRAB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3aaIiVea7nkBzRAB .icon-shape .label rect,#mermaid-svg-3aaIiVea7nkBzRAB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3aaIiVea7nkBzRAB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3aaIiVea7nkBzRAB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3aaIiVea7nkBzRAB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Phase 0
Phase 1
Phase 2-7
是
否
是
否
是
否
PROBE_BW 周期开始
时钟触发 cycle_idx 切换
pacing_gain = 1.25x (盲测)
pacing_gain = 0.75x (盲排)
pacing_gain = 1.0x (巡航)
满 1 个 min_rtt
AND (丢包 OR inflight >= probe_target)
继续当前 probe 增益
满 1 个 min_rtt
OR inflight <= 1x target
继续当前 drain 增益
满 1 个 min_rtt?
继续当前 cruise 增益
关键点:
- 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)的相位:
#mermaid-svg-FCR5MKp22dWOXO14{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FCR5MKp22dWOXO14 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FCR5MKp22dWOXO14 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FCR5MKp22dWOXO14 .error-icon{fill:#552222;}#mermaid-svg-FCR5MKp22dWOXO14 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FCR5MKp22dWOXO14 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FCR5MKp22dWOXO14 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FCR5MKp22dWOXO14 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FCR5MKp22dWOXO14 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FCR5MKp22dWOXO14 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FCR5MKp22dWOXO14 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FCR5MKp22dWOXO14 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FCR5MKp22dWOXO14 .marker.cross{stroke:#333333;}#mermaid-svg-FCR5MKp22dWOXO14 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FCR5MKp22dWOXO14 p{margin:0;}#mermaid-svg-FCR5MKp22dWOXO14 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FCR5MKp22dWOXO14 .cluster-label text{fill:#333;}#mermaid-svg-FCR5MKp22dWOXO14 .cluster-label span{color:#333;}#mermaid-svg-FCR5MKp22dWOXO14 .cluster-label span p{background-color:transparent;}#mermaid-svg-FCR5MKp22dWOXO14 .label text,#mermaid-svg-FCR5MKp22dWOXO14 span{fill:#333;color:#333;}#mermaid-svg-FCR5MKp22dWOXO14 .node rect,#mermaid-svg-FCR5MKp22dWOXO14 .node circle,#mermaid-svg-FCR5MKp22dWOXO14 .node ellipse,#mermaid-svg-FCR5MKp22dWOXO14 .node polygon,#mermaid-svg-FCR5MKp22dWOXO14 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FCR5MKp22dWOXO14 .rough-node .label text,#mermaid-svg-FCR5MKp22dWOXO14 .node .label text,#mermaid-svg-FCR5MKp22dWOXO14 .image-shape .label,#mermaid-svg-FCR5MKp22dWOXO14 .icon-shape .label{text-anchor:middle;}#mermaid-svg-FCR5MKp22dWOXO14 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FCR5MKp22dWOXO14 .rough-node .label,#mermaid-svg-FCR5MKp22dWOXO14 .node .label,#mermaid-svg-FCR5MKp22dWOXO14 .image-shape .label,#mermaid-svg-FCR5MKp22dWOXO14 .icon-shape .label{text-align:center;}#mermaid-svg-FCR5MKp22dWOXO14 .node.clickable{cursor:pointer;}#mermaid-svg-FCR5MKp22dWOXO14 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FCR5MKp22dWOXO14 .arrowheadPath{fill:#333333;}#mermaid-svg-FCR5MKp22dWOXO14 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FCR5MKp22dWOXO14 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FCR5MKp22dWOXO14 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FCR5MKp22dWOXO14 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FCR5MKp22dWOXO14 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FCR5MKp22dWOXO14 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FCR5MKp22dWOXO14 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FCR5MKp22dWOXO14 .cluster text{fill:#333;}#mermaid-svg-FCR5MKp22dWOXO14 .cluster span{color:#333;}#mermaid-svg-FCR5MKp22dWOXO14 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FCR5MKp22dWOXO14 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FCR5MKp22dWOXO14 rect.text{fill:none;stroke-width:0;}#mermaid-svg-FCR5MKp22dWOXO14 .icon-shape,#mermaid-svg-FCR5MKp22dWOXO14 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FCR5MKp22dWOXO14 .icon-shape p,#mermaid-svg-FCR5MKp22dWOXO14 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FCR5MKp22dWOXO14 .icon-shape .label rect,#mermaid-svg-FCR5MKp22dWOXO14 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FCR5MKp22dWOXO14 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FCR5MKp22dWOXO14 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FCR5MKp22dWOXO14 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 衰减公式: gain = max(1.0, probe_gain − conf·min(r_q, max_red) − conf·min(r_j, max_red) 顺序扣除)
进入 >1.0x 的增益表相位
(decay_mask 位已置位)
基础增益 = kcc_cycle_gain_tableidx
计算卡尔曼置信度
conf_scale = (p_max − p_est) × BBR_UNIT / (p_max − converged_val)
未收敛时 conf_scale < BBR_UNIT (衰减折扣)
qdelay 衰减 (预算 max_red):
扣除 min((qdelay_avg − kcc_cong_thresh) × BBR_UNIT / qscale, max_red)
缩放 conf_scale 后从 base_gain 及 max_red 中扣除
jitter 衰减 (剩余预算):
当 max_red > 0 时, 扣除 min((jitter_ewma − kcc_cong_thresh) × BBR_UNIT / jscale, max_red)
缩放 conf_scale 后从 base_gain 中扣除
base_gain 地板 = BBR_UNIT (1.0x)
不会跌破巡航水平
α = BBR_UNIT / qscale (默认 256/20000 ≈ 0.0128/μs)
β = BBR_UNIT / jscale (默认 256/16000 ≈ 0.016/μs)
qdelay 和 jitter 共用同一阈值 kcc_cong_thresh
关键点:
- 非二值开关,而是线性比例衰减 :
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"),避免无效的吞吐断崖:
#mermaid-svg-MEERsgzWfFKCgiyj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MEERsgzWfFKCgiyj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MEERsgzWfFKCgiyj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MEERsgzWfFKCgiyj .error-icon{fill:#552222;}#mermaid-svg-MEERsgzWfFKCgiyj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MEERsgzWfFKCgiyj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MEERsgzWfFKCgiyj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MEERsgzWfFKCgiyj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MEERsgzWfFKCgiyj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MEERsgzWfFKCgiyj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MEERsgzWfFKCgiyj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MEERsgzWfFKCgiyj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MEERsgzWfFKCgiyj .marker.cross{stroke:#333333;}#mermaid-svg-MEERsgzWfFKCgiyj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MEERsgzWfFKCgiyj p{margin:0;}#mermaid-svg-MEERsgzWfFKCgiyj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MEERsgzWfFKCgiyj .cluster-label text{fill:#333;}#mermaid-svg-MEERsgzWfFKCgiyj .cluster-label span{color:#333;}#mermaid-svg-MEERsgzWfFKCgiyj .cluster-label span p{background-color:transparent;}#mermaid-svg-MEERsgzWfFKCgiyj .label text,#mermaid-svg-MEERsgzWfFKCgiyj span{fill:#333;color:#333;}#mermaid-svg-MEERsgzWfFKCgiyj .node rect,#mermaid-svg-MEERsgzWfFKCgiyj .node circle,#mermaid-svg-MEERsgzWfFKCgiyj .node ellipse,#mermaid-svg-MEERsgzWfFKCgiyj .node polygon,#mermaid-svg-MEERsgzWfFKCgiyj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MEERsgzWfFKCgiyj .rough-node .label text,#mermaid-svg-MEERsgzWfFKCgiyj .node .label text,#mermaid-svg-MEERsgzWfFKCgiyj .image-shape .label,#mermaid-svg-MEERsgzWfFKCgiyj .icon-shape .label{text-anchor:middle;}#mermaid-svg-MEERsgzWfFKCgiyj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MEERsgzWfFKCgiyj .rough-node .label,#mermaid-svg-MEERsgzWfFKCgiyj .node .label,#mermaid-svg-MEERsgzWfFKCgiyj .image-shape .label,#mermaid-svg-MEERsgzWfFKCgiyj .icon-shape .label{text-align:center;}#mermaid-svg-MEERsgzWfFKCgiyj .node.clickable{cursor:pointer;}#mermaid-svg-MEERsgzWfFKCgiyj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MEERsgzWfFKCgiyj .arrowheadPath{fill:#333333;}#mermaid-svg-MEERsgzWfFKCgiyj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MEERsgzWfFKCgiyj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MEERsgzWfFKCgiyj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MEERsgzWfFKCgiyj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MEERsgzWfFKCgiyj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MEERsgzWfFKCgiyj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MEERsgzWfFKCgiyj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MEERsgzWfFKCgiyj .cluster text{fill:#333;}#mermaid-svg-MEERsgzWfFKCgiyj .cluster span{color:#333;}#mermaid-svg-MEERsgzWfFKCgiyj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MEERsgzWfFKCgiyj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MEERsgzWfFKCgiyj rect.text{fill:none;stroke-width:0;}#mermaid-svg-MEERsgzWfFKCgiyj .icon-shape,#mermaid-svg-MEERsgzWfFKCgiyj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MEERsgzWfFKCgiyj .icon-shape p,#mermaid-svg-MEERsgzWfFKCgiyj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MEERsgzWfFKCgiyj .icon-shape .label rect,#mermaid-svg-MEERsgzWfFKCgiyj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MEERsgzWfFKCgiyj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MEERsgzWfFKCgiyj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MEERsgzWfFKCgiyj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
Drain-Skip 三个必要条件
① 卡尔曼已收敛: p_est < converged_val
② 排队低于清洁阈值: qdelay_avg < kcc_clean_thresh
③ 最低驻留: delta > min_rtt / 8
进入 0.75x 排空阶段
等待最低驻留时间
delta > min_rtt >> 3 (min_rtt/8, 防抖动)
全部三个条件?
转换为 1.0x 巡航
(drain-skip 激活)
继续执行 KCC 排空门控
(AND-gate: is_full_length && drained,
- 4×min_rtt 安全超时)
与 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 控制回路的本质差异
#mermaid-svg-0QjQtxD6yJl9EYsd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0QjQtxD6yJl9EYsd .error-icon{fill:#552222;}#mermaid-svg-0QjQtxD6yJl9EYsd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0QjQtxD6yJl9EYsd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0QjQtxD6yJl9EYsd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0QjQtxD6yJl9EYsd .marker.cross{stroke:#333333;}#mermaid-svg-0QjQtxD6yJl9EYsd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0QjQtxD6yJl9EYsd p{margin:0;}#mermaid-svg-0QjQtxD6yJl9EYsd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0QjQtxD6yJl9EYsd .cluster-label text{fill:#333;}#mermaid-svg-0QjQtxD6yJl9EYsd .cluster-label span{color:#333;}#mermaid-svg-0QjQtxD6yJl9EYsd .cluster-label span p{background-color:transparent;}#mermaid-svg-0QjQtxD6yJl9EYsd .label text,#mermaid-svg-0QjQtxD6yJl9EYsd span{fill:#333;color:#333;}#mermaid-svg-0QjQtxD6yJl9EYsd .node rect,#mermaid-svg-0QjQtxD6yJl9EYsd .node circle,#mermaid-svg-0QjQtxD6yJl9EYsd .node ellipse,#mermaid-svg-0QjQtxD6yJl9EYsd .node polygon,#mermaid-svg-0QjQtxD6yJl9EYsd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0QjQtxD6yJl9EYsd .rough-node .label text,#mermaid-svg-0QjQtxD6yJl9EYsd .node .label text,#mermaid-svg-0QjQtxD6yJl9EYsd .image-shape .label,#mermaid-svg-0QjQtxD6yJl9EYsd .icon-shape .label{text-anchor:middle;}#mermaid-svg-0QjQtxD6yJl9EYsd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0QjQtxD6yJl9EYsd .rough-node .label,#mermaid-svg-0QjQtxD6yJl9EYsd .node .label,#mermaid-svg-0QjQtxD6yJl9EYsd .image-shape .label,#mermaid-svg-0QjQtxD6yJl9EYsd .icon-shape .label{text-align:center;}#mermaid-svg-0QjQtxD6yJl9EYsd .node.clickable{cursor:pointer;}#mermaid-svg-0QjQtxD6yJl9EYsd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0QjQtxD6yJl9EYsd .arrowheadPath{fill:#333333;}#mermaid-svg-0QjQtxD6yJl9EYsd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0QjQtxD6yJl9EYsd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0QjQtxD6yJl9EYsd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0QjQtxD6yJl9EYsd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0QjQtxD6yJl9EYsd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0QjQtxD6yJl9EYsd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0QjQtxD6yJl9EYsd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0QjQtxD6yJl9EYsd .cluster text{fill:#333;}#mermaid-svg-0QjQtxD6yJl9EYsd .cluster span{color:#333;}#mermaid-svg-0QjQtxD6yJl9EYsd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0QjQtxD6yJl9EYsd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0QjQtxD6yJl9EYsd rect.text{fill:none;stroke-width:0;}#mermaid-svg-0QjQtxD6yJl9EYsd .icon-shape,#mermaid-svg-0QjQtxD6yJl9EYsd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0QjQtxD6yJl9EYsd .icon-shape p,#mermaid-svg-0QjQtxD6yJl9EYsd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0QjQtxD6yJl9EYsd .icon-shape .label rect,#mermaid-svg-0QjQtxD6yJl9EYsd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0QjQtxD6yJl9EYsd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0QjQtxD6yJl9EYsd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0QjQtxD6yJl9EYsd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 本质差异
KCC: 排队测量驱导
qdelay高
qdelay低 + 已收敛
RTT采样
卡尔曼(估计T_prop)
qdelay = RTT − x_est
EWMA → qdelay_avg
线性衰减 + 卡尔曼置信缩放
floor = 1.0x
drain-skip 跳过排空
发送速率
物理网络缓冲
BBR: 增益调度 + inflight 门控
丢包/延迟
节拍驱动
cycle_idx 索引
bbr_pacing_gain\[\]
发送速率
物理网络缓冲
被动TCP降窗
增益调度 vs 排队测量驱导
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 | |
| 排空跳跃 (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 在每个节拍上叠加排队测量的自适应修正------线性衰减(非二值)、顺序消耗预算(非求和)、置信度缩放(非全量门控)。
