几种TCP拥塞控制算法的分析

几种TCP拥塞控制算法的分析

拥塞控制算法是实现TCP的重要组件,目前已有非常多的TCP Congestion Control Algorithm. 不同的算法有自己的优化特性和工作区域。首先,本文简单介绍一下TCP拥塞避免算法的工作原理;其次,介绍Reno, Vegas, Veno, Westwood Cubic的算法实现;最后,本文简单分析tcp_boost算法的工作框架。

1. TCP拥塞避免算法的工作原理


在不考虑FACK(selective ACK)的情况下[1]tcp congestion control一般包含三个阶段: slow start, congestion avoidance fast recovery. 通俗的说,slow start是指数级增长窗口(snd_cwnd),直到slow start threshold (ssthresh) congestion avoidance是加性增长窗口直到丢包(3 dupACK, 进入fast recovery)或者超时(超过RTO, 进入slow start, fast recovery是在丢包后,重设snd_cwndssthresh. 其工作状态机如图1所示:


1TCP拥塞控制状态机

        2. Reno, Vegas, Veno, Westwood Cubic

Reno是基本的AIMD(加性增乘性减算法),在slow start阶段指数增长窗口,snd_cwnd = snd_cwnd + 1 (#per ack), congestion avoidance阶段线性增长窗口, snd_cwnd = snd_cwnd + 1/snd_cwnd (#per ack)。进入fast recovery后,ssthresh = snd_cwnd/2, snd_cwnd = ssthress(+ 3)[2]

Vegasslow start阶段仍然是指数增长窗口(Reno slow start),在进入congestion avoidance后会做判断。其判断依据是N_que (中间转发设备上的队列大小)。N_que的计算逻辑是,发送窗口snd_cwnd减去带宽(近似值,利用snd_cwnd /RTT_actual来获得)*RTT(无队列时的值, 可使用监测的min RTT)。公式如下:


扫描二维码关注公众号,回复: 195941 查看本文章

Vegas的思路是通过调控snd_cwnd来控制N_que的大小,使其满足:


在算法实现时, , snd_cwnd ++, 时,snd_cwnd. 

Veno是结合VegasReno两种算法的特性来进行拥塞控制。在slow startReno slow start 方法。在congestion avoidance阶段,利用N_que来做判断:



在进入fast recovery后,同样利用来做判断:



Westwood算法基于Renoslow startcongestion avoidance阶段算法,但是其在进入fast recovery后,会根据带宽来做判断。不同于Vegas, Veno 的粗略的带宽计算方法,Westwood利用snd_una (TCP socket中数据已经确认的左边界窗口,注意是其字节值,所以最后需要除去mss_cache)来计算带宽。针对ACK Compression情况,为避免带宽过度波动,做了平滑处理(BWE = alpha * BW(k-1) + (1-alpha) * BW(k))。根据计算后的带宽,在fast recovery做以下赋值:


PS: Westwood算法的实现时,有一个小trick。以往的congestion algorithm在设置fast recovery算法时一般是通过设置struct tcp_congestion_ops 里的ssthresh函数。在实际运行中,通过回调该函数求出ssthresh值后,snd_cwnd根据ssthresh来设置新值,一般为ssthresh+3[2]。而westwood通过hook TCP eventCA_EVENT_COMPLETE_CWR, 来精确的设置snd_cwndssthresh的值。

PS:Westwood是在tcp_ca_event为 CA_EVENT_COMPLETE_CWR时设置的窗口值。这个时候,丢失的包已经重传了,发送窗口已经减半了(其利用Reno ssthresh的方法)。

fast recovery阶段要结束, 即将进入congestion avoidance。因此还是比较迷的,不知道为啥要在这里设置,而不是在ssthresh方法里设置。

Cubic算法是linux默认的tcp congestion avoidance算法。其原理非常简单,利用三次方函数来控制窗口的增长。在slow start阶段,Cubic实现hystart算法,其比Reno slow start 算法的增长速度更快。其在congestion avoidance阶段的增长函数如下所示:



C取值为0.4(在源码的bic_scale设置)。在代码实现时,每次在完成fast recovery后,都会重新设计增长函数(new epoch start, t=0),另求新的K值,公式为



控制snd_cwnd增长速率的手段,是通过设定tcp_cong_avoid_ai( socket, w, acked)里的w值来控制增长速率,使得snd_cwnd = snd_cwnd + 1/w (per ack) ≈snd_cwnd + snd_cwnd/w (per RTT)。在fast recovery阶段,snd_cwnd ≈ 0.7 * snd_cwnd(0.7为源码中的beta/1024)


        注1实现selective ACK的算法为SACK,但是由于selective ACK需要接受端的TCP协议栈做修改,所以一般的TCP拥塞控制算法不对selective ACK做处理。SACK与Reno ack(非SACK)在进入fast recovery时没有太多区别。FACK会撤销fast recovery,一般客户端实现比较少。

2:关于fast recovery阶段snd_cwnd最终是如何得到的,整个过程非常复杂。本结论参考《Linux 网络体系结构: Linux内核中网络协议的设计与实现》421页的论述。

注 2:关于fast recovery阶段,可以参考我下一篇博客。


猜你喜欢

转载自blog.csdn.net/eipi1/article/details/79868988
今日推荐