TCP依靠重传机制保证了数据的可靠性传输,同时为了避免数据发送过快而超过对方的接受能力,TCP采用了流量控制机制,(具体可以参考滑动窗口法)。但是TCP的控制机制里面只考虑到了接收端的接受能力,而忽略了一个很重要的方面,那就是没有考虑到网络自己的传输能力,从而造成了整个网络崩溃的发生。
图1.当负载超过Cliff之后,吞吐量就急剧下降,延迟相应急剧上升。Cliff点也就是网络的最大负载,一旦超过网络的整体性能就大打折扣
与上面介绍的TCP的流控比较下就可以发现,流控主要是考虑接收端,不要发送过快,超过对方的接收能力,而拥塞控制则是要考虑到整个网络环境,使其负载不能超过网络的最大承受能力。显然拥塞发生的原因是因为“需求”大于了“供给”,网络中的有限资源被多用户共享使用,网络本身无法根据资源的利用情况来限制某些用户,并且随着目前互联网的发展,上网的用户和应用的数量也随之增长,这样,如果不采取某种措施来协调资源的使用,那么拥塞的发生就是必然的。
拥塞控制是一件比较困难的事情:
目前互联网采用的是报文交换(packet-switched)网络,文交换网络使得整个网络变为分布式的,在网络中间没有连接的概念,造成了每个节点所获得的信息不是很完整,而不完整的信息要完成比较好的拥塞控制,那是非常困难的。并且互联网上各处的网络性能有很大的差异,因此控制算法还必须要有很好的适应性才行。
用塞控制算法历史:
1)TCP的拥塞控制由“慢启动(Slow start)”和“拥塞避免(Congestion avoidance)”组成。
2)又针对性的加入了“快速重传(Fast retransmit)”、“快速恢复(Fast Recovery)”算法。
3)又出现了选择性应答( selective acknowledgement,SACK)算法等。
慢启动:最初的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开始线性增加,这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。
上面讨论的两个机制都是没有检测到拥塞的情况下的行为,那么当发现拥塞了cwnd又该怎样去调整呢?
首先来看TCP是如何确定网络进入了拥塞状态的,TCP认为网络拥塞的主要依据是它重传了一个报文段。上面提到过,TCP对每一个报文段都有一个定时器,称为重传定时器(RTO),当RTO超时且还没有得到数据确认,那么TCP就会对该报文段进行重传,当发生超时时,那么出现拥塞的可能性就很大,某个报文段可能在网络中某处丢失,并且后续的报文段也没有了消息,在这种情况下,TCP反应比较“强烈”:
1.把ssthresh降低为cwnd值的一半
2.把cwnd重新设置为1
3.重新进入慢启动过程。
快速重传机制:
其实TCP还有一种情况会进行重传:那就是收到3个相同的ACK。TCP在收到乱序到达包时就会立即发送ACK,TCP利用3个相同的ACK来判定数据包的丢失(相同的ACK证明对方没收到你后续发过去的包,所以对方重复发送ack),此时进行快速重传,快速重传做的事情有:
1.把ssthresh设置为cwnd的一半
2.把cwnd再设置为ssthresh的值(具体实现有些为ssthresh+3)
3.重新进入拥塞避免阶段。
后来的“快速恢复”算法是在上述的“快速重传”算法后添加的,当收到3个重复ACK时,TCP最后进入的不是拥塞避免阶段,而是快速恢复阶段。快速重传和快速恢复算法一般同时使用。
1.当收到3个重复ACK时,把ssthresh设置为cwnd的一半,把cwnd设置为ssthresh的值加3,然后重传丢失的报文段,加3的原因是因为收到3个重复的ACK,表明有3个“老”的数据包离开了网络。
2.再收到重复的ACK时,拥塞窗口增加1。
3.当收到新的数据包的ACK时,把cwnd设置为第一步中的ssthresh的值。原因是因为该ACK确认了新的数据,说明从重复ACK时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态。
参考:http://www.cnblogs.com/fll/category/136411.html
原文:http://www.cnblogs.com/menghuizuotian/p/3757911.html