欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-17 21:00:40
...
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),即发送时间间隔与接收时间间隔的最大值。

delay-ack对BBR带宽采集的影响
具体用图来描述会比较直观,比如上图中,可以分为三步来说。

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。
delay-ack对BBR带宽采集的影响
发送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的估算是是取十轮中的最大值,这种情形的下影响确实比较小。
delay-ack对BBR带宽采集的影响
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;
-- 


相关标签: BBR delay ack