基于丢包的拥塞控制算法缺陷

  1. Bufferbloat导致的高延迟 现代网络设备内置了非常大的缓冲区,基于丢包的算法会持续增加发送速率,直到填满缓冲区导致丢包才降速。大量的数据卡在网络设备的缓冲区中,导致排队延迟增大,从而使得整体的网络出现极高的延迟和抖动。
  2. 无法区分拥塞性丢包随机性丢包 在无线网络(如Wi-Fi、4G/5G)中,丢包很常见,导致在无线网络环境下,即使网络带宽很充足,发送速率也可能因为随机的无线丢包而长期维持在一个很低的水平。
  3. Long-Fat网络上的效率低下 当这类网络发生一次丢包时,算法会立即将发送速率大幅降低)。然后以一个相对缓慢的线性速度来恢复速率。这导致带宽利用率严重不足。

BBR:基于建模的控制拥塞算法

拥塞与瓶颈

对于一个网络连接来说,在任意时刻,它在每个方向都有且只有一段最慢的链路,称之为瓶颈(bottleneck) 。

  • 瓶颈决定了连接的最大数据传输速率,就好像一根水管最细处决定了它整体的水流量。
  • 瓶颈是持久队列形成的地方。

对于瓶颈链路,只有当它的离开速率大于到达速率时,这个队列才会收缩,否则就会不断堆积,而一条链路上其他的队列也会朝着瓶颈移动(因为它的传输速率最小)。

不管一条连接会经过多少条链路,以下两个物理特性决定了传输的性能:

  • 瓶颈带宽 (Bottleneck Bandwidth, BtlBw):整个网络连接上最细的管道的最大数据传输速率。
  • 最小往返传播时间 (Round-trip Propagation Time, RTprop):数据包在完全不排队的情况下,往返一次所需的最短时间。这个值可以反映出物理链路的固有延迟。

带宽延迟积

BBR通过建模计算出一个理想的在途数据量,即 带宽延迟积 (Bandwidth-Delay Product, BDP):

\[BDP=BtlBw×RTprop\]

BDP代表了为了恰好填满整个网络管道,同时又不在路由器中产生额外排队,发送方需要发出的数据量

RTT、吞吐量与Inflight Data

  • Inflight data: 代表了在特定时间点,网络路径中正在传输的数据量。
  • BDP: 带宽延迟积。代表为了恰好填满整个网络管道而又不在任何地方产生排队,所需要注入的数据量。
  • BufSize: 网络路径中瓶颈路由器的缓冲区大小。这是路由器在转发数据包之前,能够暂存数据包的最大容量。
  • 吞吐量: 单位时间内,接收端成功接收到的数据量。

  • 当$ 0 < Inflight < BDP $时,由于Inflight data不足以填满管道,数据包在路由器中无需排队等待。
    • RTT: 此时RTT约等于RTprop,且RTT会维持在一个稳定且最低的水平。
    • 吞吐量:此时吞吐量的瓶颈不是网络的带宽,而是发送端注入数据的速率。接收端能接收多快,完全取决于发送端发送了多少。
  • 当$ BDP < Inflight < BDP + BufSize$时,超出BDP的数据量将形成一个队列,存放在路由器的缓冲区中。数据包必须等待队列中它前面的数据包被发送后才能被转发,这产生了排队时延。
    • $ RTT = RTprop + Queuing Delay = RTprop + \frac{Inflight - BDP}{BtlBw} $ RTT会随着Inflight data的增加而线性增长。
    • 吞吐量:此时网络管道已经被完全填满,吞吐量达到了系统的上限,继续增加Inflight data不会再提升吞吐量。
  • 当$ Inflight > BDP + BufSize $时,在途数据量不仅超过了网络管道的容量,还超过了路由器缓冲区的存储极限时,网络进入严重拥塞状态。当缓冲区被填满后,后续到达的数据包将被路由器直接丢弃。
    • RTT:Queuing Delay达到最大值,RTT也达到峰值。
    • 吞吐量:一旦发生丢包,会触发重传机制,实际的有效数据吞吐量会因为重传和发送速率的降低而显著下降。

BBR核心思想

BBR算法的核心目标就是让在途数据量(Inflight Data)始终维持在BDP附近, 从而获得最小的RTT和最大的吞吐量

BBR的实现

BBRv1通过一个状态机来运作,主要包含四个状态。

  1. 启动 (Startup) 阶段:快速起步,探测上限

    当一个连接刚开始时,BBR处于启动状态。这个阶段的目标是尽快地找到网络的瓶颈带宽BtlBw

    • 行为:在此阶段,BBR表现得非常激进。每当收到一个ACK确认包,它就会将发送速率翻倍,呈现指数级增长。
    • 退出条件:当BBR发现,即使发送速率在增加,但测量到的带宽(送达速率)连续几次不再有明显增长时,它就认为已经达到了瓶颈带宽。此时就会退出启动阶段。
  2. 排空 (Drain) 阶段:消除过量,降低延迟

    启动阶段的末期,由于发送速率超过了实际的瓶颈带宽,必然会在网络路径的路由器中造成一定的数据积压(排队)。排空阶段的目标就是迅速消除这些排队,将延迟降下来。

    • 行为:BBR会立即将发送速率降低到刚刚测量到的BtlBw。由于发送速率与瓶颈处理速率匹配,积压在队列中的数据包会被逐渐处理掉。
    • 退出条件:当飞行中的数据量降低到与BDP(BtlBw x RTprop)相等时,意味着多余的排队已经基本被“排空”。此时,BBR进入下一个稳定阶段。
  3. 探测带宽 (ProbeBW) 阶段:稳定运行,周期探测

    这是BBR在大部分时间里所处的状态,在此阶段,BBR的任务是在稳定发送的同时,周期性地探测网络带宽是否发生了变化。 ProbeBW阶段由一个持续8个RTT的周期性循环组成,这个循环使用了不同的步调增益 (pacing gain) 来调整发送速率。pacing_gain是一个乘数, 发送速率 = BtlBw × pacing_gain。 这个8个RTT的周期可以分解为:

    时间 pacing_gain 目的
    第1个RTT 1.25 提升速率:发送速率比当前测得的瓶颈带宽高25%,主动探测是否有更多可用带宽。这会轻微增加队列。
    第2个RTT 0.75 排空队列:发送速率降至瓶颈带宽的75%,以排空上一个RTT中可能产生的队列。
    接下来6个RTT 1.0 稳定发送:以等于瓶颈带宽的速率发送,平稳地利用网络。

    这个“增-减-平稳”的循环探测机制,使得BBR能够:

    • 及时发现带宽增加:通过周期性的1.25倍速率探测,如果网络状况变好,BBR能迅速更新其BtlBw估计。
    • 保持低延迟:探测带宽增加所造成的排队会立即在下一个RTT被0.75倍的速率排空,避免了延迟积压。
    • 公平共享带宽:在稳定期以1.0的速率发送,将带宽让给其他需要探测的连接。
  4. 探测RTT (ProbeRTT) 阶段:测量真实延迟

    BBR需要知道最真实的RTprop(无排队延迟)。但是,如果在ProbeBW阶段,网络中一直存在少量排队,那么测量到的RTT就会一直偏高。这样RTprop的估计值就会不准确,进而影响BDP的计算。

    • 触发条件:如果BBR发现,在超过10秒的时间里,它都没有测量到一个更低的RTT值,它就会强制进入ProbeRTT状态。
    • 行为:在此状态下,BBR会大幅降低发送速率,将飞行中的数据量减少到非常小的值(通常只有4个数据包)。
    • 持续时间:这个状态会持续大约200毫秒,或者一个RTT,确保有足够的时间让网络中的排队完全消失,从而测量到最真实的RTprop。之后,BBR会根据新的网络模型返回到StartupProbeBW阶段。

核心状态变量

  • BtlBw (Bottleneck Bandwidth): 瓶颈带宽的估计值。
    • 更新方式: BBR维护一个在时间窗口内(通常是过去6-10个RTT)观察到的DeliveryRate的最大值。这是一个滑动窗口最大值滤波器(max-filter)。
    • BtlBw = max(BtlBw_filter_window, DeliveryRate)
  • RTprop (Round-trip Propagation Time): 最小往返传播时延的估计值。代表了数据包在没有任何排队情况下的物理往返时间。
    • 更新方式: BBR维护一个在较长时间窗口内(BBR中是10秒)观察到的RTT样本的最小值。这是一个滑动窗口最小值滤波器(min-filter)。
    • RTprop = min(RTprop_filter_window, RTT_sample)
  • pacing_rate (Sending Rate): BBR计算出的数据包发送速率。这是BBR作为基于速率的算法的直接输出。
    • 计算方式: pacing_rate = BtlBw × pacing_gain。其中的pacing_gain是BBR在不同阶段使用的核心调节器。
  • cwnd (Congestion Window): 拥塞窗口。在BBR中,它不是主要的拥塞控制器,而是一个辅助性的上限,用于确保inflight数据量不会远超于BDP,同时兼容传统的基于丢包的恢复机制。
    • 计算方式: cwnd的目标值是target_cwnd = BDP × cwnd_gainBDP = BtlBw × RTpropcwnd_gain通常与pacing_gain联动。
    • BBR会确保cwnd >= target_cwnd,以允许数据包能以pacing_rate顺利发出。
  • inflight: 在途数据量。已发送但尚未被确认的数据总量。
  • DeliveryRate: 瞬时交付速率。在每次收到ACK时计算,用于更新BtlBw
    • 计算方式: 当一个ACK到达时,该ACK确认了N字节的数据。假设这个数据包是第k个被发送的,上一个被ACK的数据包是第j个。DeliveryRate = N / (send_timestamp_k - send_timestamp_j)。它反映了数据在网络中的实际交付速率。

Startup

目标: 快速指数级地增加发送速率,以最快速度探测到网络的瓶颈带宽BtlBw

核心参数:

  • pacing_gain: 2.89 (精确值为 2/ln(2))
  • cwnd_gain: 2.89 (精确值为 2/ln(2))

算法逻辑与计算:

  1. 设置速率: pacing_rate = BtlBw × 2.89。在连接刚开始时,BtlBw会有一个初始值,然后随着每次测量的DeliveryRate迅速增长。
  2. 设置拥塞窗口: target_cwnd = BtlBw × RTprop × 2.89cwnd被设置为不小于这个目标值,以确保不会限制数据的发送。
  3. 每次收到ACK:
    • 计算DeliveryRate并尝试更新BtlBw
    • 由于BtlBw在Startup阶段持续增长,pacing_rate也随之指数级增长。

退出条件:

  • BBR会持续跟踪BtlBw的增长情况。如果在连续3个TT周期内,新测得的BtlBw相比之前的峰值没有显著增长(增长幅度小于25%),BBR就认为已经找到了瓶颈带宽的上限。此时,它会退出Startup阶段,进入Drain阶段。

StartUp会指数级增长cwnd和pacing rate,快速探测到当前网络环境的天花板,记录下此时的RTT和BW

Drain

目标: 排空在Startup阶段末期因速率过冲而在瓶颈路由器中产生的排队。

核心参数:

  • pacing_gain: 0.346 (精确值为 ln(2)/2,即Startup增益的倒数)
  • cwnd_gain: 2.89 (与Startup相同,确保cwnd不会成为排空过程的瓶颈)

算法逻辑与计算:

  1. 设置速率: pacing_rate = BtlBw × 0.346。此时的BtlBw是Startup阶段找到的峰值带宽。由于发送速率远低于瓶颈带宽,路由器中的队列会被迅速消耗。
  2. 设置拥塞窗口: 维持与Startup阶段相同的cwnd_gain,确保cwnd足够大。

退出条件:

  • 当在途数据量 inflight 下降到等于或略低于当前估计的BDP (BtlBw × RTprop) 时,BBR认为队列已被排空。此时,它会退出Drain阶段,进入常态运行的ProbeBW阶段。

Probe_BW

  • 目标: 在大部分时间内以接近瓶颈带宽的速率稳定发送,同时周期性地探测是否存在更大的可用带宽。
  • 核心参数:
    • pacing_gain: 在一个8个RTT的周期内,按顺序使用以下值:[1.25, 0.75, 1, 1, 1, 1, 1, 1]
    • cwnd_gain: 2
  • 算法逻辑与计算:
    1. 周期性增益: BBR会维护一个指针,指向当前周期中的pacing_gain值。该指针每经过一个RTT周期就向前移动一次。
    2. 设置速率: pacing_rate = BtlBw × current_pacing_gain
      • 在增益为1.25的RTT内: 以超出瓶颈带宽25%的速率发送,主动探测更高带宽。如果网络容量变大,此时的DeliveryRate会创新高,从而更新BtlBw。这个过程会产生少量排队。
      • 在增益为0.75的RTT内: 以低于瓶颈带宽25%的速率发送,用于排空上一个RTT中产生的队列,使延迟回归正常。
      • 在增益为1的6个RTT内: 以等于瓶颈带宽的速率发送,平稳地利用带宽,并将探测机会让给其他网络流,以实现公平性。
    3. 设置拥塞窗口: target_cwnd = BtlBw × RTprop × 2cwnd_gain为2是为了允许在探测带宽时,inflight能够达到1.25 × BDP,并为网络中的一些瞬时抖动提供缓冲。
  • 退出条件:
    • ProbeBW是BBR的稳定运行状态,它会一直在此状态循环。唯一的退出条件是触发了ProbeRTT。

Probe_RTT

  • 目标: 主动减少在途数据量,使网络中的排队完全消失,从而有机会测量到真实、无干扰的RTprop
  • 触发条件:
    • RTprop的值在10秒内没有更新(即没有测量到更低的RTT)时,BBR会强制进入此状态。
  • 核心参数:
    • 此阶段不使用pacing_gaincwnd_gain进行控制。
  • 算法逻辑与计算:
    1. 保存当前cwnd: BBR会先保存进入此状态前的cwnd值,以便退出时恢复。
    2. 强制降低inflight: BBR会将cwnd强制设定为一个非常小的值,通常是4 MSS
    3. 限制发送: 由于cwnd极小,发送端会被阻塞,inflight会迅速下降到4个数据包的水平。
    4. 持续时间: 此状态持续时间为max(rtt, 200ms),并等待inflight确实下降到目标值以下,确保网络中的队列有足够的时间被排空。
  • 退出条件:
    • 在持续至少200毫秒并成功将inflight降低后,BBR会退出ProbeRTT状态。
    • 退出后,如果网络长时间空闲,可能会回到Startup阶段;否则,将直接返回ProbeBW阶段,并恢复之前保存的cwnd值,继续进行带宽探测。

参考