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),即发送时间间隔与接收时间间隔的最大值。
具体用图来描述会比较直观,比如上图中,可以分为三步来说。
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;
--
下一篇: ElasticSearch入门--索引
推荐阅读