图解丨TCP拥塞控制之基础( 三 )


 
其他部分没什么好说的,发送端会在EFS < cwnd时发送信的数据,而同时,这又会使得EFS = cwnd
 
TCP New Reno
 
根据Reno的描述,TCP发送端会在收到3个重复的ACK时进行快速重传和快速恢复,但还有有一个问题,重复的ACK背后可能不仅仅是一个包丢了!如果是多个包丢了,即使发送端快速重传了丢失的第一个包,进入快速恢复,那么后面也会收到接收端发出的多个请求其他丢失的包的重复ACK!这个时候?发送端需要再累计到3个重复的ACK才能重传!
 
问题出在哪里?发送端不能重收到的重复ACK中获得更多的丢包信息!它只知道第一个被丢弃的报文,后面还有多少被丢弃了?完全不知道!也许使用SACK(参考RFC6675)这就不是问题,但这需要两端都支持SACK 。对于不支持SACK的场景,TCP需要更灵活!
 
RFC6582中描述的New Reno算法,在Reno中的基础上,引入了一个新的变量recover,当进入快速恢复状态时(收到3个重复的ACK[a]),将recover设置为已经发送的最后的报文的序号 。如果之后收到的新的ACK[b]序号b不超过recover,就说明这还是一个丢包引起的ACK !这种ACK在标准中也称之为部分应答(partial acknowledgments), 这时发送端就不等了,立即重传丢失的报文 。

图解丨TCP拥塞控制之基础

文章插图
 
?
图解丨TCP拥塞控制之基础

文章插图
 
编辑
 
TCP在发送报文后,如果没有收到对端应答,那么在重传定时器超时后会触发重传,超时时间遵循二进制退避原则,也就是{1,2,4,8,16}这样成倍地扩大超时时间 。退避是因为TCP认为丢包意味着网络有拥塞,为了不加重网络的拥塞,TCP选择等待更长的时间再进行重传 。这和CSMA/CD中的二进制退避算法如出一辙 。
 
网络中的网络设备(路由器、交换机)在收到了超过队列限制的报文后,后续的报文会被丢弃 。从TCP采用的二进制退避算来看,TCP绝对算得上是网络里的谦谦君子了,它信守的规则是:既然已经堵了,我就等一会儿再发,如果还堵,我就再多等翻倍的时间!
 
对整个网络来说,这的确是减轻负担的好办法 。要知道,在发送窗口已满的情况下,指数退避一次,意味着单位时间内发送的报文变成了原来的1/2,再退避一次,就只有原来的1/4!就像是汽车限号出行,单双号限行不好用,我就规定一辆车只能在4天中开1天...
 
But, TCP真的需要如此克制自己吗?,换个说法,为什么TCP一定要x2退避?难道重传定时器超时时间不能线性增大(每次增加X秒),或者乘以一个更小的系数(比如x1.5) ? 我们可以从CSMA/CD找到灵感 。
 
【图解丨TCP拥塞控制之基础】CSMA/CD使用x2的原因很好理解,共享介质中的每个节点并不知道其他还有多少节点,使用x2退避就是利用二分法快速找到让整个系统稳定运行的时隙分配方案!
 
举个例子,假设系统中有4个节点发包速率相同,那么最终的稳定分配方案自然就是将一段时间分为4份,每个节点占用1个时隙 。如果此时又加入4个相同的节点 。那么显然,所有的8个节点都会发包冲突 。如何才能不冲突呢?当然是分配给每个节点的时间再减小一半!当然这里举的例子节点都是2的整数幂 。如果不是呢?此时2进制退避依然能很快地达到稳定,也许这个时候的时隙分配方案不是最合理的,但是正如前面说的,每个节点并不知道其他还有多少节点,对单个节点来说,二进制退避是最快速找到让每个节点都正常工作的方案!
图解丨TCP拥塞控制之基础

文章插图
 
?
图解丨TCP拥塞控制之基础

文章插图
 
编辑
 
二进制退避方案中隐含了对公平性的考虑,它是站在整个网络的角度,而不是其中某一台主机!
 
但对一台特定的主机,不遵守这个退避规则显然好处更多...比如使用固定的重传定时器时间 。在这种网络中,没有拥塞时大家相安无事,一旦出现了拥塞,那么不退避的主机理论上就能发出更多的报文!
图解丨TCP拥塞控制之基础

文章插图
 
?
图解丨TCP拥塞控制之基础

文章插图
 
编辑
 
当然,这似乎牺牲了其他遵守规则主机的利益,它们的重传次数会增加 。那么,如果大家都不遵守呢?结果就是大家的重传次数都增加了,拥塞甚至比大家都遵守还要糟糕,因为网络上的设备丢的包更多了!


推荐阅读