WEBRTC浅析(九)带宽估计算法之BBR

带宽估计算法之BBR

此次,主要介绍一种效率更快的带宽探测策略。BBR主要的应用是在QUIC 协议里有支持。在webrtc里,也有一段时间是放到了正式版本中。此次,我就基于WEBRTC上的BBR版本和标准的bbr协议,来给大家做个大致的讲解。

BBR带宽估计 (Bottleneck Bandwidth and Round-trip propagation time)

参考文档:https://datatracker.ietf.org/doc/html/draft-cardwell-iccrg-bbr-congestion-control
参考文档:https://www.ietf.org/proceedings/98/slides/slides-98-iccrg-an-update-on-bbr-congestion-control-00.pdf

一:BBR 的设计概述

  1. 网络路径模型

    • BBR 是一种基于模型的拥塞控制算法:BBR 的模型包括两个显式估计参数
      • BBR.BtlBw : bottleneck bandwidth(瓶颈带宽),根据最大发送数据率 获得
      • BBR.RTprop :双向往返传播延迟,根据一个窗口内发送数据的最小RTT获得
  2. 目标工作点

    • BBR 使用其模型寻找具有高吞吐量的操作点和低延迟。为了在最佳工作点附近工作(具有最大吞吐量和最小延迟的点)系统需要保持两个条件:
      1. Rate balance: 最大发送速率

      2. Full pipe:

         BDP = BBR.BtlBw * BBR.RTprop 
        
  3. 控制参数

    • BBR 使用其模型来控制其发送行为,使保持在目标工作点附近。

        1. pacing rate:BBR发送数据的速率
        2. send quantum:发送数据量
        3. cwnd:允许在飞行中的最大数据量。
      
  4. 状态机设计概述

    • BBR 希望通过一个简单的状态机改变其三个控制参数。

       通过状态机,从而实现高吞吐量、低延迟的目标。
       首先探测 BBR.BtlBw 然后探测 BBR.RTprop,通过顺序交替近似公平地共享带宽。
      
      
        BBR 从 Startup 状态开始,并提高其发送速率
       迅速地。当它估计管道已满时,它进入 Drain
       状态以排空队列。在稳定状态下,BBR 仅使用
       ProbeBW 状态 和(如果需要)ProbeRTT 状态
      
        ProbeBW 状态:定期在飞行中短暂升高以探测更高的 BBR.BtlBw 样本
        ProbeRTT 状态: 在飞行中短暂降低以探测较低的 BBR.RTprop 样本
      

4.1 状态转换图

下面的状态转移图总结了控制流程

            |
            V
   +---> Startup  ----+
   |        |         |
   |        V         |
   |      Drain   ----+
   |        |         |
   |        V         |
   +---> ProbeBW -----+
   |      ^    |      |
   |      |    |      |
   |      +----+      |
   |                  |
   +---- ProbeRTT <---+
  1. 算法组织

二:通过代码来了解

RTT, LOSE RATE的统计::bandwidth_sampler.cc

  • 计算实时发送码率

      DataSize sent_delta = sent_packet.total_data_sent -
                            sent_packet.total_data_sent_at_last_acked_packet;
      TimeDelta time_delta =
          sent_packet.sent_time - *sent_packet.last_acked_packet_sent_time;
      send_rate = sent_delta / time_delta;
    
  • 计算实时反馈码率

      DataSize ack_delta = total_data_acked_ - sent_packet.total_data_acked_at_the_last_acked_packet;
      TimeDelta time_delta = ack_time - *sent_packet.last_acked_packet_ack_time;
      DataRate ack_rate = ack_delta / time_delta;
    
  • 计算实时bandwidth

        BandwidthSample sample;
        sample.bandwidth = std::min(send_rate, ack_rate);
        max_bandwidth_.Update(sample.bandwidth, round_trip_count_);
    
  • 计算实时rtt::

        sample.rtt = ack_time - sent_packet.sent_time;
    

BBR的主要参数计算::bbr_network_controller.cc

带宽上探的过程

  1. 首先进入start up 快速上探模式
    * mode = start up
    * pacing gain = 2.885
    * 连续3个RTT target_rate > 最大带宽,判断达到 最大带宽,is_at_full_bandwidth_= true。

  2. 然后进入 drain 模式,进行排空数据
    * mode = drain
    * pacing gain = 0.34662
    * 当管道中的数据,小于一个1bdp时,认为排空结束。进入probe rtt 模式。
    * msg.data_in_flight <= GetTargetCongestionWindow

  3. 开始进入PROBE_BW模式,探测 带宽
    * EnterProbeBandwidthMode :进入 probe bw 模式
    * 通过UpdateGainCyclePhase来计算pacing gain。

  4. 稳定后的模式:
    * pacer gain: 在1.25 ,1 , 0.75 中切换.
    * 1.25 为探测带宽是否可以上溢。
    * 0.75 为排空过程。
    * 1 为带宽维持稳定的过程。

需要了解的参数:

  • 计算实时loss rate::

    • 这个是链路的真实丢包率,可以传到上层,给fec模块用来判断冗余的比例。

          if(packets_sent > 0){
           current_feedback_loss_rate_ = (float)((float)packets_lost/(float)packets_sent * 100);
          loss_rate_.UpdateWithLossStatus(msg.feedback_time.ms(), packets_sent, packets_lost);
      
  • 计算pacing_gain::

       if (round_offset == 0)
          return 1 + config_.probe_bw_pacing_gain_offset;// 1.25
        else if (round_offset == 1)
          return 1 - config_.probe_bw_pacing_gain_offset;// 0.75
        else
          return 1;
    
  • 计算当前bandwidth:

    • 这当网络没有丢包:bandwidth就是实际带宽。

    • 在有丢包率的情况:当前总带宽=bandwidth/(1-loss rate).

        实际透过率:这是服务器收到的feekback的数据,表示当前的可用带宽。
        bandwidth  = max_bandwidth_.GetBest()
      
  • 计算pacing rate::

      	DataRate pacing_rate_ = pacing_gain_ * max_bandwidth_.GetBest();
    
  • 计算cwd

       	DataSize bdp = GetMinRtt() * max_bandwidth_.GetBest();
        	DataSize congestion_window = gain * bdp;
    

三:与Paced Sender 的互动

  1. Paced_sender 是一个数据平滑发送器,他的主要作用有两个:
    * 在带宽允许的状态下,尽快的发送带宽。
    * 如果有突发的数据,则要按间隔,分多次的发送,避免造成网络拥塞。
    * Pacer 的发送模式:Pacer 内部有一个线程,定期(默认是5ms)的执行发送rtp 包的任务。

  2. Pacer 中使用的参数

    • 设置pacing和padding的 bitrate

        * setPacingRates(uint32_t pacing_rate_bps, uint32_t padding_rate_bps
        * pacing_rate_bps 是最大的可发送码率,标明媒体数据可以发送的最大带宽。
        * padding_rate_bps 是发送padding的最大码率,一般大于 等于pacing_rate_bps,当需要探测更高的带宽时,这时 媒体信源的码率不能提升,所以只能通过发送空的padding包来填充管道,来探测是否能够达到更高的带宽。
      
    • 设置pacer 增益

        * pacing_gain_ = pacing_gain;
        * 在带宽稳定的的情况下gain的值为1 。只有系统希望多发一些带宽,去探测一下当前是否有更多的带宽可以用时,会希望超发一些带宽,这个时候,Pacing gain 会 > 1.
        * 当然,当系统超发后造成的管道拥塞,就会把gain 小于1,此时会开始排空管道,减少拥塞。
      
    • 设置拥塞窗口

        * data_in_fly(管道中的数据) = data_by_send - data_by_ack 
        * congestion_window_bytes_ = congestion_window_bytes * pacing_factor_
        * 当data_in_fly(管道中的数据) > congestion_window_bytes_ 时,表示拥塞了,Pacer 需要停下来, 等待data_in_fly 下降到小于congestion_window_bytes_时,才能重新发送数据。
      
  3. Pacer的优化方向:
    * 在pacer 中多加几个rtp队列,可以精准的控制媒体流的发送顺序。
    * 对nack,media,audio进行区别对待。
    * padding包的发送,可以使用媒体包来发送,从而达到加冗余的效果,提高抗弱网的性能。

你可能感兴趣的:(webrtc)