传统拥塞控制算法并不是一蹴而就的,复杂的网络环境和用户的高要求推动着拥塞控制算法的优化和迭代,我们看下基于丢包策略的传统拥塞控制算法的几个迭代版本,如图所示:
与此同时还有一类算法是基于RTT延时策略来进行控制的,但是这类算法在发包速率上可能不够激进,竞争性能不如其他算法,因此在共享网络带宽时有失公平性,但是算法速率曲线却是很平滑,我们暂且把这类算法当做君子吧!
TCP BBR算法简介
BBR算法是个主动的闭环反馈系统,通俗来说就是根据带宽和RTT延时来不断动态探索寻找合适的发送速率和发送量。
以往大部分拥塞算法是基于丢包来作为降低传输速率的信号,而BBR基于模型主动探测。
该算法使用网络最近出站数据分组当时的最大带宽和往返时间来创建网络的显式模型。数据包传输的每个累积或选择性确认用于生成记录在数据包传输过程和确认返回期间的时间内所传送数据量的采样率。
该算法认为随着网络接口控制器逐渐进入千兆速度时,分组丢失不应该被认为是识别拥塞的主要决定因素,所以基于模型的拥塞控制算法能有更高的吞吐量和更低的延迟,可以用BBR来替代其他流行的拥塞算法例如CUBIC。
基于丢包反馈策略可能在的问题
基于丢包反馈属于被动式机制,根源在于这些拥塞控制算法依据是否出现丢包事件来判断网络拥塞做减窗调整,这样就可能会出现一些问题:
丢包即拥塞
现实中网络环境很复杂会存在错误丢包,很多算法无法很好区分拥塞丢包和错误丢包,因此在存在一定错误丢包的前提下在某些网络场景中并不能充分利用带宽。
缓冲区膨胀问题BufferBloat
网络连接中路由器、交换机、核心网设备等等为了平滑网络波动而存在缓冲区,这些缓存区就像输液管的膨胀部分让数据更加平稳,但是Loss-Based策略在最初就像网络中发生数据类似于灌水,此时是将Buffer全部算在内的,一旦buffer满了,就可能出现RTT增加丢包等问题,就相当于有的容量本不该算在其中,但是策略是基于包含Buffer进行预测的,特别地在深缓冲区网络就会出现一些问题。
网络负载高但无丢包事件
假设网络中的负载已经很高了,只要没有丢包事件出现,算法就不会主动减窗降低发送速率,这种情况下虽然充分利用了网络带宽,同时由于一直没有丢包事件出现发送方仍然在加窗,表现出了较强的网络带宽侵略性,加重了网络负载压力。
高负载丢包
高负载无丢包情况下算法一直加窗,这样可以预测丢包事件可能很快就出现了,一旦丢包出现窗口将呈现乘性减少,由高位发送速率迅速降低会造成整个网络的瞬时抖动性,总体呈现较大的锯齿状波动。
低负载高延时丢包
在某些弱网环境下RTT会增加甚至出现非拥塞引起丢包,此时基于丢包反馈的拥塞算法的窗口会比较小,对带宽的利用率很低,吞吐量下降很明显,但是实际上网络负载并不高,所以在弱网环境下效果并不是非常理想。
TCP BBR算法基本原理
前面我们提到了一些Loss-Based算法存在的问题,TCP BBR算法是一种主动式机制,简单来说BBR算法不再基于丢包判断并且也不再使用AIMD线性增乘性减策略来维护拥塞窗口,而是分别采样估计极大带宽和极小延时,并用二者乘积作为发送窗口,并且BBR引入了Pacing Rate限制数据发送速率,配合cwnd使用来降低冲击。
一些术语
BDP
BDP是Bandwidth-Delay Product的缩写,可以翻译为带宽延时积,我们知道带宽的单位是bps(bit per second),延时的单位是s,这样BDP的量纲单位就是bit,从而我们知道BDP就是衡量一段时间内链路的数据量的指标。这个可以形象理解为水管灌水问题,带宽就是水管的水流速度立方米/s,延时就是灌水时间单位s,二者乘积我们就可以知道当前水管内存储的水量了,这是BBR算法的一个关键指标,来看一张陶辉大神文章中的图以及一些网络场景中的BDP计算:
长肥网络
我们把具有长RTT往返时间和高带宽的网络成为长肥网络或者长肥管道,它的带宽延时积BDP很大大,这种网络理论上吞吐量很大也是研究的重点。
TCP Pacing机制
可以简单地理解TCP Pacing机制就是将拥塞控制中数据包的做平滑发送处理,避免数据的突发降低网络抖动。
带宽和延时的测量
BBR算法的一些思想在之前的基于延时的拥塞控制算法中也有出现,其中必有有名的是TCP WestWood算法。
TCP Westwood改良自New Reno,不同于以往其他拥塞控制算法使用丢失来测量,其通过对确认包测量来确定一个合适的发送速度,并以此调整拥塞窗口和慢启动阈值。其改良了慢启动阶段算法为敏捷探测和设计了一种持续探测拥塞窗口的方法来控制进入敏捷探测,使链接尽可能地使用更多的带宽。
TCP WestWood算法也是基于带宽和延时乘积进行设计的,但是带宽和延时两个指标无法同时测量,因为这两个值是有些矛盾的极值,要测量最大带宽就要发送最大的数据量但是此时的RTT可能会很大,如果要测量最小的RTT那么久意味着数据量非常少最大带宽就无法获得。
TCP BBR算法采用交替采样测量两个指标,取一段时间内的带宽极大值和延时极小值作为估计值,具体的实现本文就不展开了。
发送速率和RTT曲线
前面提到了BBR算法核心是寻找BDP最优工作点,在相关论文中给出了一张组合的曲线图,我们一起来看下:
1.曲线图示说明:
这张图是由两个图组合而成,目前是展示[数据发送速率vs网络数据]和[RTTvs网络数据]的关系,横轴是网络数据数量。
两个纵轴从上到下分别为RTT和发送速率,并且整个过程分为了3个阶段:应用限制阶段、带宽限制阶段、缓冲区限制阶段。
2.曲线过程说明:
app limit应用限制阶段
在这个阶段是应用程序开始发送数据,目前网络通畅RTT基本保持固定且很小,发送速率与RTT成反比,因此发送速率也是线性增加的,可以简单认为这个阶段有效带宽并没有达到上限,RTT是几乎固定的没有明显增长。
band limit带宽限制阶段
随着发送速率提高,网络中的数据包越来越多开始占用链路Buffer,此时RTT开始增加发送速率不再上升,有效带宽开始出现瓶颈,但是此时链路中的缓存区并没有占满,因此数据还在增加,RTT也开始增加。
buffer limit缓冲区限制阶段
随着链路中的Buffer被占满,开始出现丢包,这也是探测到的最大带宽,这个节点BDP+BufferSize也是基于丢包的控制策略的作用点。
3.一些看法
网上有一些资料都提及到了这张图,其中的一些解释也并不算非常清晰,结合这些资料和自己的认识,笔者认为在网络链路的缓存区没有被使用时RTT为最小延时MinRTT,在网络链路缓冲区被占满时出现最大带宽MaxBW(链路带宽+链路缓存),但是此时的MaxBW和MinRTT并不是最优的而是水位比较高的水平,有数据表明按照2ln2的增益计算此时为3BDP,整个过程中MinRTT和MaxBW是分开探测的,因为这二者是不能同时被测量的。
BBR算法的主要过程
BBR算法和CUBIC算法类似,也同样有几个过程:StartUp、Drain、Probe_BW、Probe_RTT,来看下这几个状态的迁移情况:
StartUp慢启动阶段
BBR的慢启动阶段类似于CUBIC的慢启动,同样是进行探测式加速区别在于BBR的慢启动使用2ln2的增益加速,过程中即使发生丢包也不会引起速率的降低,而是依据返回的确认数据包来判断带宽增长,直到带宽不再增长时就停止慢启动而进入下一个阶段,需要注意的是在寻找最大带宽的过程中产生了多余的2BDP的数据量
Drain排空阶段
排空阶段是为了把慢启动结束时多余的2BDP的数据量清空,此阶段发送速率开始下降,也就是单位时间发送的数据包数量在下降,直到未确认的数据包数量
ProbeBW带宽探测阶段
经过慢启动和排空之后,目前发送方进入稳定状态进行数据的发送,由于网络带宽的变化要比RTT更为频繁,因此ProbeBW阶段也是BBR的主要阶段,在探测期中增加发包速率如果数据包ACK并没有受影响那么就继续增加,探测到带宽降低时也进行发包速率下降。
ProbeRTT延时探测阶段
前面三个过程在运行时都可能进入ProbeRTT阶段,当某个设定时间内都没有更新最小延时状态下开始降低数据包发送量,试图探测到更小的MinRTT,探测完成之后再根据最新数据来确定进入慢启动还是ProbeBW阶段。
我们来看一下这四个过程的示意图:
曲线说明:这两个坐标给出了10Mbps和40msRTT的网络环境下CUBIC和BBR的一个对比过程,在上面的图中蓝色表示接收者,红色表示CUBIC,绿色表示BBR,在下面的图中给出了对应上图过程中的RTT波动情况,红色代表CUBIC,绿色代表BBR。
TCP BBR算法的一些效果
有一些文章认为BBR有鲜明的特点,把拥塞控制算法分为BBR之前和BBR之后,可见BBR还是有一定影响,但是BBR算法也不是银弹,不过可以先看看BBR算法在谷歌推动下的一些应用效果,其中包括吞吐量、RTT、丢包率影响:
从图中我们可以看到在YouTube应用BBR算法之后,就吞吐量普遍有4%左右的提升,特别地在日本的提升达到14%,RTT的下降更为明显平均降低33%,其中IN(猜测是印度地区)达到50%以上,在丢包率测试中BBR并不想CUBIC那么敏感,在丢包率达到5%是吞吐量才开始明显下降。
开启bbr
开机后 uname -r 看看是不是内核 >= 4.9
执行 lsmod | grep bbr,如果结果中没有 tcp_bbr 的话就先执行
modprobe tcp_bbr
echo "tcp_bbr" >> /etc/modules-load.d/modules.conf
执行
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
保存生效
sysctl -p
执行
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
如果结果都有 bbr, 则证明你的内核已开启 bbr
执行 lsmod | grep bbr, 看到有 tcp_bbr 模块即说明 bbr 已启动