有趣的TCP BBR ProbeRTT行为点滴

本来昨晚跟同事商量好在群里内卷一把的,结果一想到还有正经事要办,就把内卷这事给忘了。

BBR ProbeRTT状态的目标有两个:

  • 保持BBR的基本特征,即重新测得RTprop。
  • 保持BBR算法的公平收敛。

第一个目标很容易理解,将inflight保持为4个段至少1个RTT(200ms和1个RTT取大值),这个可以确保管道中自己占据的queue已被清空,第二个目标稍微有点隐晦,可以参考我之前的文章:
https://zhuanlan.zhihu.com/p/388339486

先再直观描述一下,然后看几个值得优化的点。

在BBR的paper中有下面的图文:
在这里插入图片描述
“bigger flows to yield bandwidth to smaller flows”是如何发生的呢?

数学推导在我前面的文章中,但仅是直观观察,这个收敛也是很明确的。

假设RTT相同,传输时间相同,定义一下大象流和老鼠流:

  • 大象流:传输总字节数很大的流。
  • 老鼠流:传输总字节数偏小的流。

当老鼠流进入ProbeRTT而大象流还没有进入该状态时,大象流依然占据着queue,老鼠流进入ProbeRTT时queue尚未排空,这会导致老鼠流测量到的RTprop比实际的RTprop偏大,更大的RTprop将会得到更大的cwnd从而导致更多的inflight(可以通过带宽实际增益系数 1.25 × R T p r o p R T p r o p + D e l a y q u e u e \dfrac{1.25\times RTprop}{RTprop+Delay_{queue}} RTprop+Delayqueue1.25×RTprop看出来),这样就会利好老鼠流。

反过来,如果大象流首先进入ProbeRTT呢?这是很有意思的,ProbeRTT状态将全局同步。

一旦大象流进入ProbeRTT,queue会大量排空,所有流都会同时测得自己的RTprop,由于BBR算法中ProbeRTT间隔是固定的10s,因此所有流将会在10s后同时进入ProbeRTT,这也就解释了为什么上图中每隔10s所有流在同一个时间点都会有一个向下凸起的小尖尖。

实际上,只要大象流进入ProbeRTT就可以满足其它流测到RTprop,其它流也就不必再进入ProbeRTT,这个状态是非常损耗性能的。但问题是TCP没有全局视角,也就是说谁也不知道自己是大象流还是老鼠流。

办法就是随机化。

filter_expired = after(tcp_jiffies32,
				bbr->min_rtt_stamp + min_rtt_win_sec/2 * HZ + 
				next_pseudo_random32(tcp_jiffies32)%10);

将固定的10s间隔改为以10s为平均值的随机间隔,比如在5s到15s中取随机值,作为下一次进入ProbeRTT的时间。既不影响收敛,还能提高性能。

擦除这个全局同步向下的小尖尖对于类似直播这种卡顿率攸关的流非常重要,特别是RTT小于20ms的流(下面会提到200ms的事)。

老鼠流率先进入ProbeRTT,如前所述,其偏大的RTprop会导致其inflight增加,趋向于公平,大象流率先进入ProbeRTT,其它流均将不必再进入ProbeRTT,维持在ProbeBW状态,在200ms时间内依靠ProbeBW的1.25倍速增益抢夺大象流腾出来的带宽,这也将趋向于公平。

这里的200ms是一个可调节的参数,由于BBR的max-filtered带宽的维持窗口是10个RTT,对于RTT小于20ms的流来讲,4个段的cwnd持续200ms将会导致ProbeRTT之前的bltBW滑移到窗口外,重新进入ProbeBW之后将无法继承之前的高带宽。在内网环境,我倾向于将该值调小。

另外的一个点就是,RTT在20ms以下的流,是否有必要大规模部署BBR。BBR的建议参数应该是Google的场景,200ms和10s的关联在于:BBR uses 200ms to approximately bound the performance penalty of PROBE_RTT’s cwnd capping to roughly 2% (200ms/10s).

分布较广的随机间隔让某个流率先进入ProbeRTT的概率增加,大象流率先进入ProbeRTT可以防止老鼠流再次进入ProbeRTT,而反过来,老鼠流率先进入ProbeRTT,由于老鼠流并没有腾出多少queue空间,大象流早晚还是要进入ProbeRTT。是不是很自适应呢?

万事有个前提,没了前提就是但是。

以上结论的前提是BBR在自己的场子里玩,一旦混入了CUBIC,事情就复杂了。下面基于此复杂性介绍一个关于BBR的优化。

上周,同事推荐我一个视频:
https://www.youtube.com/watch?v=kC4gApsx-uU

视频一共13分钟,上班时间看视频有划水摸鱼之嫌,13分钟的视频我看了40分钟…

问题展现在下面这个截屏中:
在这里插入图片描述
大象流进入ProbeRTT并不会阻止CUBIC流继续抢占queue,如果在纯BBR的场子,上图应该是下面的样子:
在这里插入图片描述
视频里给出的方案很简单,与其维持固定的10s为周期进入ProbeRTT状态,不如主动发现queue堆积:
在这里插入图片描述
该视频发布于2020年11月,算是日本人对BBR的一种魔改吧,背后的思路就是要解决BBR如何自适应与CUBIC共存时面面临的问题。

这里面的难度是调参数,一旦超过2个参数,靠手艺调得一手好参数几乎就非常困难。所以按照范雅各布森的基础理论,把参数确定是个方法。

Ratioth确定为2是合适的,理由来源于雅各布森管道容量的推导,详情参见:
https://zhuanlan.zhihu.com/p/353272282
这也是Reno算法MD系数以及ssthresh的由来。

BBR ProbeRTT从固定10s的周期性触发,改为了事件触发,在1s到10s内只要srtt与RTprop比值超过2就进入ProbeRTT,该机制规定了两个边界,即两次ProbeRTT最小间隔为1s,最大间隔为10s,可以非常好地与CUBIC自适应共存了,如果没有CUBIC,BBR依然大致是10s为周期进入ProbeRTT。


浙江温州皮鞋湿,下雨进水不会胖。

Guess you like

Origin blog.csdn.net/dog250/article/details/119451856