delay-ack对BBR带宽采集的影响

BBR算法带宽时延积BDP是最为重要的一个变量,而公式BDP = Bw * min_RTT,即等于链路带宽乘以最小传输时延,Bw和min_RTT的准确性直接影响了最终BBR算法的传输效果。
min_RTT的估算,是通过不断比较记录一个最小的rtt值,如果超过10s没有更新过min_RTT,则进入到Probe_RTT模式中,将发送数据量减小到4个包,来探测当前的最小min_RTT值。这种方式其实也会存在很多问题,比如直播服务来说,经常会出现隔10秒钟,码率下降的问题,但这个不是本文讨论的重点。
BBR算法另一个需要计算的重要变量带宽Bw,带宽给人的直观印象是数据包通过网络传输的速度,BBR算法中的定义为:
带宽 = delivered / interval;
delivered 为时间T内交付到对端的数据包个数,这里的交付包括对端ack确认的数据包,SACK确认的数据包以及D-SACK确认的数据包。
interval为输出时间间隔,max(snd_interval, ack_interval),即发送时间间隔与接收时间间隔的最大值。


具体用图来描述会比较直观,比如上图中,可以分为三步来说。

1,tcp收到a数据包的确认,会在传输控制块中记录最近被交付到对端的数据包a的交付时间T1,发送时间为Ta,此时交付到对端的数据包总数为D1,。
2,收到a的确认后,又可以发送一个新的数据包b,此时会将T1,Ta,D1,以及数据包b的发送时间Tb,记录在数据包b的skb信息里。
3,数据包b被确认时,此时的时间为T2,交付到对端的数据包个数为D2,会从数据包b的skb里取出T1,Ta,Tb, D1,计算发送时间间隔Tb-Ta,接收时间间隔T2-T1,交付数据量D2-D1,
带宽=(D2-D1) /max(T2-T1, Ta-Tb)。

看懂了上面的带宽计算过程后,来看看delay-ack对带宽计算的影响吧,假设传输过程如下图,红色代表原始数据包发送,一共发送了6个数据包,而灰色的代表了ack数据包,一共两个ack,一个确认了skb1和skb2,一个确认了skb3到skb6。

发送skb3,skb4,skb5,skb6的skb信息块的D1是相同的,即发送时交付到对端的数据包个数为2。而当收到第二个ack数据包时,因为这时一下确认了4个包,对于接收时间间隔是相同的,但是对于发送时间间隔是不同的,因为skb3到skb6的发送时间是不相同的,内核中选择的是第一个数据包skb3的发送时间,在tcp_clean_rtx_queue()函数中,会调用tcp_rate_skb_delivered()来进行采样,红色标出的位置说明,只有一个ack确认的所有数据包中的记录D1不相同,才会更新rs->interval_us,也就是发送时间间隔。直观来说T_snd < T_ack,所以计算带宽时似乎影响不大,因为即使选择skb6,计算出来的T_snd 也大概率是小于T_ack。
void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb,
			    struct rate_sample *rs)
{
	struct tcp_sock *tp = tcp_sk(sk);
	struct tcp_skb_cb *scb = TCP_SKB_CB(skb);

	if (!scb->tx.delivered_mstamp.v64)
		return;

	if (!rs->prior_delivered ||
	    after(scb->tx.delivered, rs->prior_delivered)) {
		rs->prior_delivered  = scb->tx.delivered;
		rs->prior_mstamp     = scb->tx.delivered_mstamp;
		rs->is_app_limited   = scb->tx.is_app_limited;
		rs->is_retrans	     = scb->sacked & TCPCB_RETRANS;

		/* Find the duration of the "send phase" of this window: */
		rs->interval_us      = skb_mstamp_us_delta(
						&skb->skb_mstamp,
						&scb->tx.first_tx_mstamp);//delivered 与prior_delivered 发送时间差

		/* Record send time of most recently ACKed packet: */
		tp->first_tx_mstamp  = skb->skb_mstamp;
	}
	/* Mark off the skb delivered once it's sacked to avoid being
	 * used again when it's cumulatively acked. For acked packets
	 * we don't need to reset since it'll be freed soon.
	 */
	if (scb->sacked & TCPCB_SACKED_ACKED)
		scb->tx.delivered_mstamp.v64 = 0;
}

但是上图中第一ack确认也是delay_ack,也是skb信息块中记录相同的交付到对端的数量0。所以第一个ack处理中记录了最近被交付到对端的数据包的发送时间是skb1的发送时间,并不是skb2的发送时间。因此得出了下图,可以看到这时候T_snd似乎更大了,假如前一个ack累计确认了100个包,第二ack就确认了两个数据包,那很有可能第二个计算出来的带宽值偏小了。当然,这种误差只存在连续的ack都是累计确认了好多个数据包的情况下,并且Bw的估算是是取十轮中的最大值,这种情形的下影响确实比较小。

BBR作者也提供了一个patch,但是还未并入到master中,可以看到当记录tx.delivered相同时,是会更新使用最晚发送的数据包的发送时间,上图中就是skb2和skb6的对应的发送时间。

diff --git a/net/ipv4/tcp_rate.c b/net/ipv4/tcp_rate.c
index ed02e11ed537d..7be4979c607ad 100644
--- a/net/ipv4/tcp_rate.c
+++ b/net/ipv4/tcp_rate.c
@@ -84,7 +84,9 @@ void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb,
 		return;
 
 	if (!rs->prior_delivered ||
-	    after(scb->tx.delivered, rs->prior_delivered)) {
+	    after(scb->tx.delivered, rs->prior_delivered) ||
+	    (scb->tx.delivered == rs->prior_delivered &&
+	     skb->skb_mstamp > tp->first_tx_mstamp)) {
 		rs->prior_delivered_ce  = scb->tx.delivered_ce;
 		rs->prior_delivered  = scb->tx.delivered;
 		rs->prior_mstamp     = scb->tx.delivered_mstamp;
-- 


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值