BBR算法分析以及在可靠udp传输中的应用

目录

1.BBR简介

2.BBR算法中的bandwidth、BDP、inflight bytes、cwnd、pacing rate概念

3.BBR算法整体组成

4.带宽测量

5.STARTUP状态

6.DRAIN状态

7.PROBE_BW状态

8.PROBE_RTT状态

9.BBR算法的应用


1.BBR简介

BBR(bottleneck bandwidth and RTT)算法是google提出的一个用于网络拥塞控制的算法,在linux的内核以及QUIC中均有BBR算法的实现。一直觉得纯看书、看代码,没有动手没有思考很难掌握一个新知识,为了更好的体验BBR算法的优势以及分析其实现,于是采用了chromium项目中的bbr算法代码,实现了一个可靠udp传输模块quick,项目地址:

https://gitee.com/keplearn/quick.git

通过quick, 可以感受到quick与tcp的抗丢包能力的差异,而导致这种差异的很大原因就在于采用的拥塞控制算法不同。

传统的RENO、CUBIC拥塞算法是基于丢包的,检测到丢包就会认为链路发生了拥塞,从而降低发送速度。而实际上丢包不等于链路发生了拥塞,数据包在网络传输中会通过不同的路由器和交换机,这些路由器和交换机有shallow buffer也有deep buffer,在shallow buffer中丢包在没有拥塞前就可能会发生,而在deep buffer中,丢包会在产生拥塞后才会发生。同时在wifi、移动通信中,信号噪音也可能会导致丢包,这也并不等于网络发生了拥塞。

BBR算法与RENO、CUBIC不同,它没有采用基于丢包的方式来评估带宽,而是基于带宽测量方式来计算链路的可用带宽,结合统计得到的最小rtt,然后计算出一个合适的数据包发送时间,通过控制数据包的发送时间,最终实现带宽的最大化利用以及传输最小rtt。

2.BBR算法中的bandwidth、BDP、inflight bytes、cwnd、pacing rate概念

bandwidth:BBR算法评估出的链路可用 带宽。

BDP:带宽延迟积(bandwidth delay product),bdp = bandwidth * min_rtt。

inflight bytes:发送端已发送但是未收到ack消息的字节数。

cwnd:拥塞控制窗口,cwnd与BDP、cwnd_gain有关,在一定程度时可认为cwnd的值就等于BDP。cwnd限制了inflight bytes,inflight bytes不能超过cwnd。

QuicByteCount Bbr2Sender::GetTargetCongestionWindow(float gain) const {
  return std::max(model_.BDP(model_.BandwidthEstimate(), gain),
                  cwnd_limits().Min());
}

pacing rate:步进速率,由bandwidth和pacing_gain决定。pacing rate在计算数据包的发送延迟时间时会被用到。

void Bbr2Sender::UpdatePacingRate(QuicByteCount bytes_acked) {
  if (BandwidthEstimate().IsZero()) {
    return;
  }

  if (model_.total_bytes_acked() == bytes_acked) {
    // After the first ACK, cwnd_ is still the initial congestion window.
    pacing_rate_ = QuicBandwidth::FromBytesAndTimeDelta(cwnd_, model_.MinRtt());
    return;
  }

  QuicBandwidth target_rate = model_.pacing_gain() * model_.BandwidthEstimate();
  if (startup_.FullBandwidthReached()) {
    pacing_rate_ = target_rate;
    return;
  }

  if (target_rate > pacing_rate_) {
    pacing_rate_ = target_rate;
  }
}

3.BBR算法整体组成

BBR算法可分为4个状态startup、drain、probe_bw、probe_rtt,4个状态的转换图如下:

连接刚建立时进入startup状态,在startup状态下会以指数的方式增加发送速度,以 便快速发现链路可用带宽。然后进入drain状态,在drain状态会清空在startup状态中过量发送的数据,使得inflight的数据不大于BDP(带宽延迟积)。随后进入probe_bw状态和probe_rtt状态,BBR算法的绝大部分时间都处于probe_bw和probe_rtt状态,这4个状态的具体作用以及实现将在下面逐个进行分析。

在开始分析BBR算法前先作个说明,不对代码中的具体数字作解释,这些变量取为什么取这个值就适合或者说是最好的,而不是其它的值。这或者是基于统计而得到,或者是前后有什么数学理论支撑。例如 float startup_full_bw_threshold = 1.25,为什么是1.25而不是1.15或者1.35。。。

4.带宽测量

因为bbr算法是基于带宽测量的,因此带宽的计算便是算法的一个关键点。为实现带宽计算,bbr算法会跟踪最近收到ack消息的包,同时记录所有发出的包。当一个包收到ack消息时(A_1),就能得到这个包发送时的信息(S_1),同时也能得到前一个收到ack消息的包的信息(A_0、S_0),利用这些信息就可以计算出send rate和ack rate。

send_rate = (bytes(S_1) - bytes(S_0)) / (time(S_1) - time(S_0));

ack_rate = (bytes(A_1) - bytes(A_0)) / (time(A_1) - time(A_0));

ack_rate很明显就是接收端的接收速度,这个速度可以做为带宽值。但考虑到一个ack包内部可能确认了多个数据包,所以会出现ack_rate > send_rate的情况,因此获取带宽值的时间还需要做个限制:rate_sample = min(send_rate, ack_rate);

5.STARTUP状态

在startup状态,设置初始拥塞容器大小为 cwnd_ = 32 * kDefaultTCPMSS = 46720,其中kDefaultTCPMSS是在linux中最大tcp包大小,其值为1460。在startup状态下,pacing_gain_和cwnd_gain_都被设置为2.885,也就是发送速度变为原来的2.885倍。若连续3次得到的带宽值相比前一次的带宽值增长都不通过25%,则说明接近了带宽瓶颈,这个时候就需要进入drain状态。

为什么需要连续出现3次带宽增长不超过25%才退出startup?官方文档的说法是为有足够的证据证明当前的平稳带宽并不是因为接收窗口的限制而导致的,通过3次的的判断,可以允许接收者自动调整接收窗口,让发送者得到更高的带宽评估值。

6.DRAIN状态

drain状态是为清空在startup状态下发送的在网络中处于排队状态的数据包。在drain状态下,pacing_gain_被设置为 1.0 / 2.885,这样实际的发送速度就会被快速降低,一直到飞行中的数据量小于或者等于BDP,这个时候就认为网络中没有数据包是处于排队的了,就进入到probe_bw状态。

7.PROBE_BW状态

bbr算法的绝大部分时间都处于probe_bw状态下,probe_bw状态的核心就是通过周期性设置不同的pacing_gain来发现链路的可用带宽。probe_bw状态又可分为三个子状态,分别为probe_up、probe_down、probe_cruise,对应的pacing_gain分别为1.25、0.75、1.0, 这些状态最多持续一个rtt的时间。

probe_up状态提高发送速度,用来探测是否有更多的可用带宽。probe_down,用于清空在probe_up状态下发送的在网络中处于排队状态的数据包。probe_cruise状态下,数据包在链路中的排队时间足够短,同时带宽也能充分利用。

8.PROBE_RTT状态

probe_rtt状态的存在是为了探测到链路中最小的rtt,从而得到最合适的BDP。在最初版本的bbr算法中,probe_rtt状态下拥塞窗口被设置为1460,这个值 是linux下默认的一个tcp包的最大长度;而在bbr2算法中拥塞窗口大小不变,pacing_gain_和cwnd_gain_都被设置为1.0,最终的结果就是发送速度维持不变。bbr2相比bbr的这个改变,我感觉最大的好处是能够更充分的利用带宽,毕竟probe_rtt状态会持续200ms, 每间隔10s就会进入probe_rtt状态,也就是有2%的时间是处于probe_rtt状态的,如果这2%的时间都拥塞窗口都被设置为1460,那就相当于带宽资源被闲置了2%,这是一个不小的损失。

9.BBR算法的应用

bbr算法是一个拥塞控制算法,它可以应用于任何需要进行拥塞控制的传输场景。https://gitee.com/keplearn/quick.git 是一个利用了bbr算法实现拥塞控制的可靠udp传输模块,使用quick可以实现高效、可靠的udp传输。在利用bbr进行拥塞控制时需要注意ack的时间间隔,也就是接收端在收到数据包到发出ack消息的时间间隔,这个间隔应当控制在4~5ms,不且过大也不且过小。间隔过大容易影响传输速度,过小的话则容易导致发送端计算ack_rate时忽大忽小,从而导致带宽评估不准确,带宽实际利用率下降。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值