TCP 拥塞避免算法( 五 )


估计带宽时候还一个需要处理的 , 跟 RTT 不同 , RTT 是只要有应用层数据发就能测得 , 就能更新估计值 , 但 BtlBw 的话必须应用层有足够数据发才能估计 。所以下图可以看到有个 App Limited 。BBR 会将因为 app 没足够数据发而导致测得的 BtlBw 过小的情况丢弃 , 只记录有足够数据发的情况下得到的 BtlBw 。实际上链路中实际 BtlBw 是个 hard limit , 就是无论我们怎么测都不可能超过链路上实际 BtlBw , 所以只要在窗口内测得小的 BtlBw 都可以丢掉 , 就用测试周期内最大的 BtlBw 。

TCP 拥塞避免算法

文章插图
 
来自[4]
BBR 的状态机BBR 在控制拥塞时候会在一组状态之间进行切换 , 如下图:
TCP 拥塞避免算法

文章插图
 
来自[2]
先简单介绍一下下面再针对每个状态更细一些说 。初始状态就是 Startup , BBR 因为不知道当前带宽到底是多少 , 也会有类似 Slow Start 的过程 , 逐步增加发送速度探测 BtlBw 。等到探测到 BtlBw 后因为 Startup 阶段发了很多数据出去 , inflights 很大 , 可能链路会有排队 , 所以进入 Drain 阶段去做清理 , 让链路上的队列清空;之后进入稳定期 , 会周期性的在 ProbeBW 和 ProbeRTT 两个状态之间进行切换 , 间歇的探测 BtlBw 和 RTprop 。
BBR 稳定期工作机制先记录稳定期再写 Startup 等 。BBR 每收到一个 ACK  , 就会估计 RTprop 和 BtlBW (deliveryRate) , 尽力保证 inflight 数据量跟估计得到的 BDP 差不多 。BBR 下 inflights 数据量由内部的 target_cwnd 控制 , 而 target_cwnd 是个比 BDP 稍微大一点点的量 。
假设链路上 RTprop 和 deliveryRate 一直保持不变 , BBR 处在稳定状态一直发送数据 , 它保证 inflights 的数据量不会超估计的 BDP 很多 。此时链路上 Bottleneck 在发送端 , 由发送端控制发送速度 。如果链路上带宽提高了 , 因为 Bottleneck 在发送端 , 发送端会感知不到带宽变化 。所以 BBR 需要周期性的提高发送速率将 Bottleneck 从发送端移到链路上去探测链路上的带宽 , 这就是 ProbeBW 状态的来源 。名字也可以看出它含义是探测带宽 , 探测的是链路上 Bottleneck 的带宽 。
ProbeBW 状态下先开始增周期 , 即提高发送率到稳定期的 1.25 倍 , 直到出现丢包或 inflights 数据量达到 1.25 倍 BDP 为止 。观察延迟是否升高 , 如果延迟升高且 deliveryRate 不变 , 说明链路上带宽没有变化且产生了队列堆积;接下来会进入减周期 , 降低发送率到稳定期的 0.75 倍 , 等待一个 RTprop 或 inflights 数据量低于 BDP 为止 , 用以让链路上在增周期出现堆积的队列清空 。之后再保持 inflights 等于 BDP 稳定数个 RTprop 后再次开始增周期 。
之前提到 BBR 每次收到 ACK 会尝试更新 RTprop , 而 RTprop 取的是窗口期内最低的 RTprop 。如果 BBR 运行了很长时间一直没有更新 RTprop , 即很长一段时间都没有比当前使用的 RTprop 更低的 RTprop 时 , BBR 会进入 ProbeRTT 状态 , 用于探测 RTprop 。比如链路上带宽出现减少 , 链路上出现堆积 , 保持发送速度或继续进行 ProbeBW 的话会让链路上堆积更加严重 , RTT 上升 。所以 RTprop 一直不会被更新 。
ProbeRTT 下 BBR 将 CWND 降到很低的值 , 典型的是 4 个 MSS , 持续一段至少 200ms 或一个 RTprop 。这么一来 Inflights 数据量会突降 。再判断链路是否处在 full_pipe 状态 , 是的话则进入 ProbeBW , 不是则进入 Startup 。
full_pipe 判断主要是靠最近的增周期中 , 发送率提高后 deliveryRate 是否有大幅度增加 , 有相应幅度的增加说明链路可能还没有满载 , 我们加快发送速率还是能发的出去 , 没增加则表示链路是满载的 , 发送速度加快但是接收速率没跟上 。有个 Linux 内的 BBR 实现  , 可以看 。
之前提到了 RTprop 和 BtlBw 两个量是测准一个另一个就测不准 , 稳定期测量这两个值的任务大多数时候都由 ProbeBW 独自完成 , 在增周期提高发送带宽发多数据到链路探测 BtlBW , 在减周期减小发送带宽减少发送速率从而减小 Inflights , 看估计的 RTprop 是否降低 , 降低了则说明测到了最新的 RTprop 。如果很长时间都没有更低的 RTprop 出现 , 可能链路发生了切换 , 这时候才需要切换到 ProbeRTT 去探测最新的 RTprop 。从 ProbeRTT 的机制能看到它对性能是有影响的 , 所以 BBR 是尽力减少 ProbeRTT 时间占比 , 大部分时间都在 ProbeBW 状态 。


推荐阅读