BBR cwnd_gain 的循环依赖 bug

同事咨询了一个有趣的问题,bbr 在probe bw 状态下,rtt 变小了,但采集到的 delivery date 却没变,此时算出来的 cwnd 变小,限制了 sender 发送。这种情况应该调什么参数。

这是 bbr 一个典型的循环依赖 bug,迟至 bbr3 才稍微解决,详见 bbrv3 fix 2。简单说,interval 变小,delivery rate = delivered / interval 本应变大,但由于 cwnd = interval * delivery rate * cwnd_gain 限制了 inflight,导致 delivered 也变小,就循环依赖。

简单推导一下原因。先看 bbr 最大可利用的 buffer。

max_inflight = cwnd_gain * probe_up_gain * delivery_rate * interval

将当前 bbr 参数配置代入上式:

max_inflight = 2 * 1.25 * delivery_rate * interval = 2.5 * BDP

因此:

max_buffer_used = max_inflight - BDP = 1.5 * BDP

这意味着超过 1.5 * BDP 的 buffer 是 bbr 无法利用(这其实是好事)的,在 deep buffer 和背景流共存时非常吃亏。另一方面,BDP = delivery_rate * interval,当 interval 变小时,BDP 变小,这直接进一步减少了 max_buffer_used 的上限,即使进入随后的 probe up 阶段,也无力突破这个由于 interval 减少而降低的上限,更别提 cruise 阶段直接削减 inflight 了。

bbr3 直接将 probe up 阶段的 cwnd_gain 改成了 2.25,bbr1 的改法如下:

case BBR_PROBE_BW:
        bbr->pacing_gain = (bbr->lt_use_bw ?
                                BBR_UNIT :
                                bbr_pacing_gain[bbr->cycle_idx]);
        // 我直接改成了 3,改成 2.5,2.25 都行
        bbr->cwnd_gain   = bbr->pacing_gain > BBR_UNIT ? BBR_UNIT * 3 : bbr_cwnd_gain;
        break;

直接硬调还是粗暴了,万一遇到更 deep 的 buffer 呢,要进一步增加 cwnd_gain 吗?

大可不必为保持和 cubic 在 deep buffer 的公平性而有意伸展 cwnd_gain,否则就倾向于变成 cubic。2x 的 cwnd_gain 足用,保持不退缩即可。

设 delta_interval 为新老 interval 之差,则 delta_max_buffer_used = 1.5 * delivery_rate * delta_interval,保持该值为 0,算出 delta_cwnd_gain 即可,附加到用新的 cwnd_gain 进行 probe up,则始终保持 buffer 最大用量不超过 BDP 的一定比例。

保持 probe up 阶段的抢占性不因自身测量行为被削弱,而不是无条件放宽 inflight 限制而提高 buffer 最大用量,deep buffer 非标,不应作为算法假设,除非在实践中可体现,但不是算法本身。此外,提高 cwnd_gain 在 shallow buffer 下还会造成高丢包。

索性再粗暴一点,不要改代码,直接将 cwnd_gain 参数改成 3,调参即可,意思差不多,丢包多点儿,不过反正也不在乎,重传猛就行。

delivery_rate * (interval_prop + interval_queuing)

皮鞋没有蹬上,露着白袜子。
浙江温州皮鞋湿,下雨进水不会胖。

你可能感兴趣的:(bug,bbr)