拥塞控制:排水终止的两种决策:OR 与 AND

发布时间:2026/6/12 1:01:20

拥塞控制:排水终止的两种决策:OR 与 AND 拥塞控制排水终止的两种决策OR 与 ANDPROBE_BW 的周期由 8 个相位构成6 个巡航1.0x pacing、1 个上探1.25x、1 个下探0.75x。下探的任务是在上探将 inflight 推到 BDP 之上后以低于瓶颈速率的 pacing 使多余 inflight 消退。下探的终止条件决定了消退进行到什么程度才认为完成。终止条件对外暴露的代码量很小——只有一行 OR 或一行 AND——但其背后所对应的假设、信任分配和失败模式构成了两个拥塞控制实现之间最集中的分岔点之一。以下不是关于哪条路更好的争辩——而是逐一展开设计者所面对的权衡空间以及各自认为合理的取舍。一、OR 门以时间为尺的排水条件设定BBR 的原始排水终止条件为is_full_length || drained。is_full_length定义为从排水相位开始至今已经历至少一个 min_rtt使用而非以确保相位在时序边界上不会过早结束。drained定义为当前在途数据量inflight at EDT已经降至 1.0x pacing 增益下的 BDP 估计。满足二者之一排水即告终止。设计者的推理路径这个设计建立在一个对 BDP 模型的信任上如果 min_rtt 是准确的max_bw 是准确的那么inflight ≤ BDP在物理上等价于 bottleneck buffer 为空。不需要进一步验证——模型本身已经给出了排水的数学条件。如果模型是可信的那么在任何时间点上inflight 降至 BDP 这一条件本身就足以确认排水完成。但模型的可信度不是绝对的min_rtt 窗口可能在排水期间采样到一个新的更低值max_bw 可能被排水阶段的低 inflight 压低。is_full_length的另一个角色是为模型的不确定性提供时间上限——即使模型在排水期间偏离最多也只浪费一个 RTT 的排水时长。因此 OR 门的逻辑可以读作一个 RTT 之后无论模型是否已确认排水完成排水都结束。选择持续排水更长的时间能获得更准确的 BDP 确认——但设计者认为模型本身已经足够好不需要这个额外的确认。定时排水的合理性单流路径上一条流在上探产生的多余 inflight 量是确定的。上探以 1.25x pacing 运行一个 min_rttinflight 从大约 1.0 BDP 升至约 1.25 BDP。产生的超额是 0.25 BDP。下探以 0.75x pacing 运行一个 min_rtt 的 infight 降幅约为 0.25 BDP——恰好等于上一相位的超额。在这个理想模型下一个 min_rtt 是排水的自然时间长度。没有进一步的验证——不需要等待drained的实际确认——不是因为设计者看不清潜在的偏离而是在这个特定的路径假设下单流、稳定 BDP、不重叠上探上探的多余 inflight 与排水速率形成一个精确的 1:1 抵消关系。等待额外的确认不会改变结果只会释放已排空的 buffer 后被更慢的速率继续占用。有意的时序偏差BBR 不使用delta min_rtt而使用delta min_rtt的判断方式。允许在恰好满一个 min_rtt 的 ACK 到达时立即终止排水——这个 ACK 本身可能仍然反映着排水刚启动时的 inflight 状态因为 ACK 的反馈有至少一个 RTT 的延迟此时drained的判断基础是偏早的。强制相位至少多等一个 ACK——不是逻辑必须的是一个工程上的余量。二、多流集体队列的形成共享瓶颈上的上探叠加当 N 条独立 BBR 连接共享一个物理瓶颈时每条流的上探相位随机分布于它们的独立 8-相位周期中。在任何给定的时刻期望有 N/8 条流处于上探状态1.25x pacing剩余的流分布在巡航1.0x和下探0.75x之间。聚合 pacing 产出的 inflight 为聚合 inflight (N/8) × 1.25 BDP_per_flow (6N/8) × 1.0 BDP_per_flow (N/8) × 0.75 BDP_per_flow简化后约为 N × 1.0 BDP N/8 × 0.25 BDP。超出了瓶颈容量 N × BDP 的那部分多出来的 0.25 BDP 条数的累积不来自任何一条流单独的 pacing而来自它们在同一时间间隔内的独立上探被叠加到了同一个瓶颈 buffer 中。时间折叠在一个 200ms RTT 的路径上一个 PROBE_BW 周期持续 8 × 200ms 1.6 秒。上探相位占据 200ms——每条流在这 200ms 内独立推送 1.25x inflight。N 条流的相位各不同步——它们在不同时间点开始和结束上探。但瓶颈 buffer 不区分谁的 inflight——它只看到总 inflight 的瞬时值。在时间折叠下任何时候都有多个流在推动超过其稳态份额的 inflightbuffer 中的集体队列大于任何一个流自己估计的 BDP。OR 门在此路径上的行为各条流在自己的周期中各自运行排水——各自进入下探相位独立执行is_full_length || drained。is_full_length条件在每条流的本地时钟满一个 RTT 时触发——不检查全局的 inflight 状态、不比较其他流的队列进展。N 条流的is_full_length在时间上有先后但整体在一个比较窄的窗口内依次触发。此时任何一条流的drained条件几乎肯定不成立——集体队列远超该流的独立 BDP 估计。在 OR 门下is_full_length先于drained成立排水退出。但此时集体队列的总量并没有减少到瓶颈容量以下——它只是被一轮排水部分削减了而已。下一轮巡航以 1.0x pacing 运行inflight 在此水平上维持——不增不减。再下一轮上探再次堆叠到了已经存在的残留队列上CWND 在连续几个周期内不断爬升直到触发丢失。这个过程不是任何一个单条流的失误——是 OR 门对超越单流的聚合 inflight 没有提供结构性的感知。三、AND 门以物理量为尺的排水条件替换KCC 将终止条件替换为(is_full_length drained) || safety_timeout。和 OR 门的区别仅在于中间的||变成了——然而这一个运算符的改变把排水从基于时间的定时退出改为了基于测量值的验证退出。为什么设计者认为这样更合理AND 门背后的判断是时间本身不是排水完成的有效证据。时间过去了只说明等待了多久不说明队列是否真的已经清空。因为外部队列来源——其他流的 inflight、其他 CC 算法的流量、ACK 压缩效应——都会使 inflight 的下降速率偏离 BDP 模型预测的线性。drained是对现实的确认is_full_length是对确认之前的必要等待的约束。两个同时成立才构成一个完整的排水已完成的断言。这个设计不假设 BDP 模型一定能跟上队列的实际变化。它把模型交给实际测量去验证——它更谨慎但代价是等待时间更长。实现bool drained kcc_packets_in_net_at_edt(sk, rs-prior_in_flight, etd_bw) kcc_inflight(sk, max_bw, BBR_UNIT, ext); return (is_full_length drained) || delta kcc-min_rtt_us * KCC_DRAIN_TARGET_MAX_RTTS;kcc_packets_in_net_at_edt是 BBR 的对 in-flight 的 EDT 感知估计——它计算从瓶颈发送到 ACK 返回这一段时间内在路上还有多少数据。kcc_inflight(sk, max_bw, BBR_UNIT, ext)计算的是 1.0x 增益下 BDP 的目标 inflight。对比的逻辑是在途数据量是否已经降到了目标 BDP 之下。这个比较不会在is_full_length成立之前进行——is_full_length仍作为必要条件因为在一个 RTT 之内ACK 的反馈还不反映排水开始之后的 inflight 下降测量值是滞后的。多流收敛速度在 8 流、1 Gbps 瓶颈、约 200ms min_rtt 的路径上上探的集体队列可能使每条流的 inflight 在峰值触及 2.0-2.5 BDP。从峰值排到 1.0 BDP 的过程有几个 min_rtt 的长度——is_full_length在一个 RTT 后成立但drained要等到再多 1-2 个 RTT 后才成立。AND 门在这些额外的轮次中保持 0.75x pacing直到 inflight 确实回降到 1.0x 水平。四、安全超时触发条件delta kcc-min_rtt_us × KCC_DRAIN_TARGET_MAX_RTTS默认 4 个 min_rtt在 AND 门等待超过 4 个 min_rtt 后无条件终止排水。单独存在的必要性AND 门的结构中没有天然的时间终止——如果drained永远不成立排水将永不终止。这种情形不是理论上的——在瓶颈被永久竞争流量占据时例如一个非 BBR 连接以恒定速率占据 bufferAND 门看不到任何使 inflight 降到 BDP 之下的机会继续 0.75x 排水只会使 inflight 降到不合理的低值造成 self-starvation。安全超时是这条路径上的保底策略。它不等同于排水已完成——它等同于排水已放弃。相位被强制切换到 cruise让 1.0x pacing 在正常的 cycle 中重新开始竞争。4 个 RTT 的选择这不是一个基于精密度量的常数。选择 4 是出于对竞争持续性的经验估计——在 RTT 200ms 的条件下4 个 RTT 大约 800ms覆盖了绝大多数排队确实在递减、只是比较慢的场景2-3 个 RTT并留出一个缓冲轮次。不是一个最优解是一个不会过早也不会过晚的经验中点。五、Kalman drain-skip上探后无队列即不排水AND 门的补充策略AND 门的确认延迟在单流路径上是纯粹的空等——一条流的上探队列在一个 RTT 内就已经自己排完了drained条件在is_full_length成立的同一时刻就已经为真。AND 门却仍要同时检查两者结构上的确认延迟对单流场景没有提供任何新的信息。KCC 的应对不是修改 AND 门本身而是在排水条件评估之前增加一条单独的检查——在特定的信号组合下整个排水直接被判定为不需要下探相位当巡航处理。三个信号Kalman 已收敛ext-p_est kcc_kalman_converged_p_est_val默认 500。误差协方差 p_est 降至收敛阈值以下说明 RTT 估计已达到稳态——没有未解释的偏差来源。Queue delay 接近零ext-qdelay_avg kcc_drain_skip_qdelay_us_val默认 1000μs。Kalman 估计的 average queue delay 小于 1ms——表明 buffer 内部几乎没有排队累积。它由 Kalman 的传播延迟估计与 raw RTT 样本之间的差值得出相比直接观察 RTT sample 对单个 min_rtt 的变化敏感度差但在统计上比单一样本更稳定。与上次排水的间隔充足delta kcc-min_rtt_us / KCC_DRAIN_SKIP_MIN_RTT_DIV默认为 min_rtt 的八分之一。防止在连续的瞬时 ACK 中没有经过充分的时间间隔即再次触发第一和第二个条件。它不是排水状态判断的一部分——它保护判断本身不受 ACK 节奏的干扰。三个信号共同指定的含义当 Kalman 说明 RTT 估算是稳定的p_est 低并且 buffer 几乎是空的qdelay 低那么可以推断出上探的 1.25x pacing 在这一轮没有产生一个显著的队列。如果上探没有产生显著队列——排水的理由就不存在。不需要一个额外的逻辑来确认或否认这一点。排水直接跳过。这里存在一个 Kalman 收敛后的隐含信任——收敛后的状态推断是可靠的。如果对 Kalman 的估计准确性有保留那么这个跳过是不安全的。但算法的设计者做了一个判断收敛后的 RTT 估计在各条路径上的可靠性足以支持这个跳过。六、OR 门的结构偏重BDP 模型的自证OR 门把排水的判定权交给了 BDP 的模型推算值。在模型可信的范围内这产生了一个简洁有效的行为——排水周期长度固定、可预测、不需要外部 observability。BBR 的带宽和 RTT 估计是共享一个滑动窗口的一致性在其内部是保证的。但这种自证只能在单流路径上完整成立。当 BDP 的估计因为外部队列的存在而发生偏移时——max_bw 在多流竞争中被压低min_rtt 仍然保持——BDP 的推算值偏低。此时drained判据已经不再反映真实的瓶颈状态——它是自证的闭环。OR 门对此没有保护——因为它不期望超出模型解释能力的外部事件发生。这既不是设计的漏洞也不是模型本身的缺陷——在设计者的假设空间内外部的聚合队列是分配模型的低概率场景。对一个通用算法来说将设计建立在会有人帮我处理外部性的隐含前提上是一个简化的选择——不是错误的但不是一个不面临这种场景的选择。可预测性的成本定时排水产生了一个行为可预测的循环。对于线上监控、参数调优、吞吐分析而言每个相位的时长是常数行为的任何偏差都可以从样本中检测。OR 门的这个特性对运维是有价值的。但同时可预测性意味着它不会对现实中的不可预测做出结构性的应对。这个交换是合理的——不是因为它总对是因为设计者认为在绝大多数部署环境中不可预测的聚合队列的出现频率低于可预测周期带来的好处。七、AND 门的时间成本确认延迟的分解AND 门中drained在is_full_length成立后的额外等待来自于测量 lag——当is_full_length成立时对应着排水启动时的数据的 ACK 刚刚返回。此时 inflight 的 EDT 估计可能正在下降但尚未在 DSP 上反映。到drained成立为止的额外延迟包含两个成分ACK 返回的反馈延迟和实际排水所需的物理时间。在 RTT 为 5ms 的单流链路上这个额外延迟通常在 1-5ms 范围。对于一个 8 相位、总长约 40ms 的完整 PROBE_BW 周期额外的 1-5ms 约为 2.5%-12.5% 的额外周期时间。这不是一个可忽视的量——它足够大到可以在吞吐基准测试中产生可观测的差异。Kalman drain-skip 的成本回收在这条单流链路上当 Kalman 三个条件同时成立时排水被完全不执行。AND 门的确认延迟不存在——没有产生过排水没有需要确认的。干净链路上的单流传输在 Kalman 收敛后的第一个上探相位之后即隐式完成排水下探不产生额外时间成本。AND 门在多流碰撞时的确认延迟是在产生实际价值的等待真实队列排空而在单流无碰撞时被跳过——成本和收益的结构是对称的。八、两种判断体系的并置将kcc_is_next_cycle_phase的完整源码展开可以看到排水终止的决策层级Kalman drain-skip三个条件满足 → 判为已完成 → 不执行排水AND 门 超时两个条件都满足 → 排水完成否则在 4 个 RTT 后强制结束纯巡航is_full_length单一条件 → 经过一个 RTT 即完成这三个层级在一个函数中顺序求值各自维护各自的条件集合互不假设对方的状态。实际运行中哪一层被激活完全由实时测量决定——与设计者的选择无关。三层都是可单独操作的判断单元组合使用而不是替代。九、合理性而非完美性OR 门和 AND 门都是在某个特定假设下被判定为合适的排水机制。OR 门的设计者认为模型是充分的——BDP 的自身定义提供了足够的信息来判断排水何时完成。AND 门的设计者认为需要观察——等待外部测量确认 inflight 确实降到了预期的水平。没有一条路能在所有假设下都表现出色。OR 门在多流碰撞下会经历队列堆积AND 门在稳定单流下付出额外的等待时间。每一种设计选择了自己的侧重点——没有一个是解决问题的那个但各自解决了一个层面的不确定性。选择 AND 门不是因为 OR 门有什么可以被替代的设计缺陷。是设计者看到了一个在多流 VPS 场景中频繁出现的路径条件、判断其值得一个专用的策略路径。OR 门的设计者对这个问题可能也有自己的处理办法——可能在一个不同的位置可能选择接受它。两种选择都是合理的。在 TCP 拥塞控制的长期经验中一个合理的设计往往在它自身的假设下表现良好在不同的假设下出现不同类型的故障。设计者的工作是理解这种选择而非撤销它。Tags: TCP, BBR, KCC, drain, cycle phase, multi-flow, congestion control, algorithm design

相关新闻