全部博文(695)
分类: 系统运维
2014-06-17 20:22:41
原文地址:tcp拥塞控制 作者:yunmingtan
一图胜千言,看上面的图,上面是负载-吞吐量,下面是负载-延迟,问题很明显了,受限于网络节点的物理承受能力,负载显然不可能和吞吐量成线性关系,当负载在Knee点的时候,吞吐量在一个较高的水平,同时数据包的延迟也较小,网络处于一个较好的状态,Knee点到Cliff点,吞吐量增长缓慢,延迟确增长很快,网络性能已经开始下降,而Cliff点就是该网络的最大负荷点,吞吐量达到最大,再往后网络就崩溃了。拥塞控制包括拥塞预防,和拥塞恢复两部分,前者使得网络尽可能在Knee点,后者在网络处于不良或是崩溃状态后尽可能恢复。
为什么拥塞控制相当困难?
困难源于复杂,如果是电话网络这种电路交换网络,显然就没这问题。但是互联网是基于报文交换的,没有中心节点,无法做出统一的管理。没有连接,使得任何节点不可能获得完整的信息。同时控制协议本身的流量又必需要尽可能的少。这都使得拥塞控制非常难于实现。
下面的谈论,为了方便期间,假定每个TCP包文都按照MSS来发送。
拥塞控制的对象?
拥塞的原因是负载过大,控制的对象自然是发送者的流量,TCP中用于控制流量的是滑动窗口协议。窗口的大小取决于对端通告的接收窗口(rwnd)和拥塞控制窗口,即真正的发送窗口=min(rwnd, cwnd)
慢启动?
最初的TCP在连接建立成功后会向网络中发送大量的数据包,这样很容易导致网络中路由器缓存空间耗尽,从而发生拥塞。因此新建立的连接不能够一开始就大量发送数据包,而只能根据网络情况逐步增加每次发送的数据量,以避免上述现象的发生。具体来说,当新建连接时,cwnd初始化为1个最大报文段(MSS)大小,发送端开始按照拥塞窗口大小发送数据,每当有一个报文段被确认,cwnd就增加1个MSS大小。这样cwnd的值就随着网络往返时间 (Round Trip Time,RTT)呈指数级增长,事实上,慢启动的速度一点也不慢,只是它的起点比较低一点而已。我们可以简单计算下:
开始 ---> cwnd = 1
经过1个RTT后 ---> cwnd = 2*1 = 2
经过2个RTT后 ---> cwnd = 2*2= 4
经过3个RTT后 ---> cwnd = 4*2 = 8
如果带宽为W,那么经过RTT*log2W时间就可以占满带宽
拥塞避免?
从慢启动可以看到,cwnd可以很快的增长上来,从而最大程度利用网络带宽资源,但是cwnd不能一直这样无限增长下去,一定需要某个限制。TCP使用了一个叫慢启动门限(ssthresh)的变量,当cwnd超过该值后,慢启动过程结束,进入拥塞避免阶段。对于大多数TCP实现来说,ssthresh的值是 65536(同样以字节计算)。拥塞避免的主要思想是加法增大,也就是cwnd的值不再指数级往上升,开始加法增加。此时当窗口中所有的报文段都被确认时,cwnd的大小加1,cwnd的值就随着RTT开始线性增加,这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。
如何检测拥塞?
首先来看TCP是如何确定网络进入了拥塞状态的,TCP认为网络拥塞的主要依据是它重传了一个报文段。上面提到过,TCP对每一个报文段都有一个定时器,称为重传定时器(RTO),当RTO超时且还没有得到数据确认,那么TCP就会对该报文段进行重传,当发生超时时,那么出现拥塞的可能性就很大,某个报文段可能在网络中某处丢失,并且后续的报文段也没有了消息,在这种情况下,TCP反应比较“强烈”:
1.把ssthresh降低为cwnd值的一半
2.把cwnd重新设置为1
3.重新进入慢启动过程。
从整体上来讲,TCP拥塞控制窗口变化的原则是AIMD原则,即加法增大、乘法减小。可以看出TCP的该原则可以较好地保证流之间的公平性,因为一旦出现丢包,那么立即减半退避,可以给其他新建的流留有足够的空间,从而保证整个的公平性。