bbr算法比较简单也比较容易理解,全部关于它的优化也就一样不复杂了。
请注意,任何优化都只针对特定场景的,根本不存在一种听任四海而皆准的算法。咱们分析Google的测试报告时,比较容易被忽视的是其bbr算法的部署场景。若是能够完美复现Google的B4网络,那么测试结果应该就跟Google是一致的,但不得不说,bbr算法内置了不少的参数(目前的版本中是写死的),Google方面有没有调整这些参数是未知的。咱们先看一下bbr算法是怎么利用空余带宽的。
bbr算法最终会稳定在Steady-state,即其PROBE_BW的状态,该状态内置了一个小循环,bbr在这个循环中不停运转:算法
注意其中的速率增益:1|1|1|1|1|1|1.25|0.75|1|1|1|1|1|1|1.25|0.75|1|...这个循环增益彻底是bbr自主的循环增益,不受任何外界控制,是否进入下一个增益取决于如下的判断:
1.正增益周期,是否在不丢包状况下已经填满了可用带宽,这个旨在提升资源利用率(效率因素);
2.减损周期内,是否已经腾出了部分能够资源,这个旨在知足公平性(公平因素);
3.平稳反馈周期是否足够久,使得共享资源的TCP链接有时间收敛到一个公平的位置(公平因素)。
这是个典型的效率优先兼顾公平的实例,可是咱们能够看到,若是上述的第三点,即平稳反馈周期过久会怎样?很显然,这样的话会下降bbr的抢占性和灵活性,bbr发现带宽富余的最短期就是6个RTT,这对于某些场景而言显然是不足的。所以,咱们能够得出第一个结论:
PROBE_BW状态中平稳反馈周期的长度决定了bbr抢占敏感性。
一个最简单且极端的例子,若是咱们将bbr在PROBE_BW的pacing gain数组改为下面这个样子,其将会第一时间发现带宽富余,然则代价就是发送速率的颠簸,这对下载业务是好的,可是并不利于直播点播业务:数组
// 将8个元素的数组改为2个元素的数组,是的bbr在Steady-state处于颠簸徘徊状态。 static const int bbr_pacing_gain[2] = { BBR_UNIT * 5 / 4, /* probe for more available bw 油门*/ BBR_UNIT * 3 / 4, /* drain queue and/or yield bw to other flows 刹车*/ // BBR_UNIT, BBR_UNIT, BBR_UNIT, /* cruise at 1.0*bw to utilize pipe, */ // BBR_UNIT, BBR_UNIT, BBR_UNIT /* without creating excess queue... */ };
这个比较相似与那些有事没事鸣着喇叭的110车,无论路上多么堵,它们一遍遍拿着喇叭喊着”靠边!靠边!“,老是能过得去,估计司机也是一脚油门一脚刹车踩的很辛苦(我并无说120和119,那是由于120和119没事的话不敢这么玩,医生和消防武警仍是牛不过警察的)。
接下来咱们来看第二个话题,那就是bbr的崖点在哪?
咱们知道,Reno/CUBIC直接在膝点出采起措施,使得拥塞得以免,即使是持续保持慢速,也不会到达崖点,Reno/CUBIC将丢包做为到达膝点的标志,而后退出拥塞控制算法,进入拥塞恢复阶段,直到拥塞被认为缓解恢复正常,是不会把控制权再度交给拥塞控制算法的。这也是经典的拥塞控制风格做风,本质就是在膝点采起措施,避免从崖点跌落,这即是经典的锯齿之由来!锯齿尖的位置,那是膝点,而不是崖点!
那么bbr是否是也相似呢?非也!由于bbr不会被接管,bbr本身全程负责全部的拥塞处理!事实上,bbr根本无论什么拥塞不拥塞,它只是单纯的根据本身收到的带宽反馈来计算下面发送的带宽,即使真的发生了拥塞,不也仍是能够发送数据的么,只是发送的多是重传数据而不是新数据而已。
咱们来看一张来自Google的bbr测试结果图示:缓存
问题我已经标在上面了,为何bbr会面临一个崖点,此后彻底不可恢复!虽然CUBIC最终也是归于同一结局,可是它是按比例滑落的,而不像bbr那样跌落通常。这个怎么解释呢?这个问题有同事和坛子里的都问过我,但我并无给出正面回答,由于我以为咱们本身很难模拟真实的丢包环境。第一,咱们没有模拟任意丢包率的独立仪器(丢包不受TCP发送量的影响,就算只发一个包,该丢也得丢),咱们所谓的丢包几乎都是因为咱们本身形成的,是咱们本身的TCP形成的,其次,能认识到第一点事实的人不多,明白现有Linux TCP拥塞状态机逻辑和拥塞控制算法逻辑关系的人更少。这样一来若是测出的结果没有发现崖点,那即是无休止的毫无心义的争论。无神论者永远都只能是个什么什么者,那只是它们本身相信没有神,让他们去说服基督徒,那是会被打死的,虽然,基督徒也不能证实有神!
因此,我通常而言会尽力避开这种争论,不管任何方面,即使我知道的再多,我也会争取作一名沉默的人。
我直接给出答案吧,崖点的存在,正是由于bbr_pacing_gain数组的固定配置。
崖点的存在是一种”资不抵债“的退避措施!咱们看到在bbr_pacing_gain数组中,其增益元素的增益比是1/4,也就是25%,能够简单理解为,在增益周期,bbr能够多发送25%的数据!
注意看上面的图的横轴丢包率,当丢包率接近25%的时候,曲线从崖点跌落,这并非偶然的!过程很容易理解,首先,在增益期,x%的丢包率是否抵消了增益比25%?也就是说,x是否大于25。
咱们假设x就是25!那么可想而知,25%的收益彻底被25%的丢包所抵消,至关于没有收益,接下来的减损周期,又减小了25%的发送数据,同时丢包率依然是25%...再接下来的6个RTT,持续保持25%的丢包率,而发送率却仅仅基于反馈,即每次递减25%,咱们能够看到,在bbr_pacing_gain标识的全部8周期,数据的发送量是只减不增的,而且会一直持续下去,这就是崖点!
以上个人假设是x就是25,事实上,丢包率在不足25%的时候,以上的减损现象就已经开始呈现了,在Google的测试中,咱们发现从5%的丢包率开始,持续到10%左右的丢包率,而后到15%~20%丢包率的时候,吞吐率持续下跌,一直跌到底。咱们能够看到,在bbr_pacing_gain数组中,除了bbr_pacing_gain[0]表示增益以外,在有丢包的状况下,其它的都是减损,特别在高丢包率(我一贯以为5%以上就是很高丢包率了)下更是明显。
好了,咱们把上述的论述总结在一个图示上:网络
而后咱们获得的新结论是:
1.bbr_pacing_gain数组的bbr_pacing_gain[0]系数(当前是5/4),决定了抗丢包能力;
2.bbr_pacing_gain数组中系数为1(即平稳反馈周期)的元素的多少,决定了抗丢包能力(过久,则会持续衰减,过短,则比较颠簸)。
咱们从Google的bbr部署说明里也能够看出:
CUBIC’s loss tolerance is a structural property of the algorithm, while BBR’s is a configuration parameter.
As BBR’s loss rate approaches the ProbeBW peak gain, the probability of measuring a delivery rate of the true BtlBw
drops sharply, causing the max filter to underestimate.
其中为何会”causing the max filter to underestimate“呢?由于max filter是基于时间窗口的,随着时间的流逝,bbr会忘掉以前的大带宽,只记着如今因为丢包持续减小的小带宽。你要注意,其实只要有丢包,在6个平稳反馈周期内,带宽就是持续减小的,然而,问题是,这些减小的量能不能经过增益周期,即bbr_pacing_gain[0]的收益一次性补偿,若是不能,那么跌入崖点就是必然的。
所以,拿什么来抵抗丢包呢?答案是损失一点公平性,用增益系数去换!我把5/4换成了3/2,效果良好,大概到丢包率30%之后才跌入崖点,要知道30%的丢包率,可用性几乎已经能够说是零了!另外,我为何不减小bbr_pacing_gain数组中增益系数为1的元素的数量呢?由于这会严重影响公平性!因此我保持其8个元素。
这是bbr不如CUBIC的地方,bbr事实上彻底基于反馈,正常来说按照VJ的数据守恒规则,一个包离开另外一个方可进入的状况下,丢包率自己就会持续拉低带宽,bbr有一个5/4的增益,这可能会弥补丢包带来的反馈减损,然而增益系数5/4倒是一个配置参数,当丢包率大于25%的时候,就会资不抵债!甚至丢包率在10%~15%的时候,bbr的表现就开始不佳。所以,若是能动态计算丢包率,而后将丢包率反馈给增益系数,动态计算增益系数,我想效果应该会不错。好比丢包率达到25%的时候,增益系数就变成50%,这样就能够避免因为丢包带来的反馈减损,然而,你又如何判断这些丢包是噪声丢包仍是拥塞丢包呢?答案在于RTT!只要时间窗口内的RTT不增长,那么丢包就不是拥塞致使的,感谢Gail & Kleinrock给出的模型,感谢Yuchung Cheng & Neal Cardwell证实了这是对的。
顺便说一句,因为CUBIC的表现就是填满全部能够填满的缓存,它们的行为是可怕的,要不是CUBIC还遵循着乘性减窗(只是减到了原来的0.7而不是0.5),网络估计早就崩溃了,即使如此,若是不是由于大量的TCP接收端限制了接收窗口,网络也是要被CUBIC搞崩溃的。现现在,有将近30%~50%的接收端通告了一个比CUBIC计算出来的更小的窗口,感谢这些接收端,使得咱们免受CUBIC Flood的危害!app