TCP的拥塞控制 (四)
NewReno是在Reno的基础上,改进了Fast Recovery,主要思想是保证处于network中的packet的总量是饱和的。
在Reno算法中,一个超时会导致相应的那个packet的重传,然而,一个超时发生时,本可以重传多个潜在的丢包,但Reno算法没有这样实现,这就导致性能不高。
Reno在遇到多包丢失时,存在两个问题:一个是,大量的包没有足够的重复ACK触发重传,只能等待超时才能得以重传。第二个是,即使采取措施(在Partial Acknowledgement一节中已有所讨论)避免了超时,也会存在Multiple Fast Retransmits和严重的window reduction现象,这些会影响TCP的性能。在Multiple Fast Retransmits一节中,我们讨论了相应的解决方案。NewReno正是在此方案的基础上进行的改进。
NewReno添加一个recover变量,作为Fast Recovery阶段的一个阈值,当sender成功发送到recover所标识的packet时,Fast Recovery阶段才结束。这里成功发送的标志是收到来自receiver的正常ACK。
每当进入Fast Recovery阶段时,recover都更新为high_seq(当前已经发送出去的packet的最大序号),而在进入Fast Recovery阶段之前,recover中保持的是上一个Fast Recovery阶段更新的recover的值。实际上,recover表示的是当前窗口中,可能的丢包的最大序号,Fast Recovery阶段的目标就是恢复这里面的所有的丢包,因此,recover是Fast Recovery阶段的边界。
NewReno不允许Multiple Fast Retransmits,因此在收到3次重复ACK时,如果TCP已经处于Fast Recovery阶段,则不会进行Fast Retransmit。并且,即使TCP没有处于Fast Recovery阶段,NewReno还会判断重复ACK中的序号是否大于当前recover的值(当前recover的值实际是上一个Fast Recovery阶段的recover的值)。如果小于,则说明ACK指明的packet是上一轮Fast Recovery已经处理过的packet,其肯定已经在上一轮被重传了,之所以仍然有3次重复ACK,可能是乱序或者重复发送receiver端已经存在的packet导致的,并不意味着丢包,因此不需要重传。如果大于,则说明这是一个显然的丢包,会进入Fast Recovery进行处理。
进入Fast Recovery之后,会继续收到重复ACK,直到收到非重复ACK为止,这期间的操作与传统的Reno一致,NewReno的特别之处体现在处理非重复ACK的环节。
当收到一个非重复ACK时,这个ACK可能响应的是Fast Retransmit重传的packet,也可能是Fast Retransmit之后重传的packet。由于多包丢失的存在,这个ACK可能是Full ACK或者Partial ACK,对这两种ACK会采取不同的处理方式。
如果ack_seq>recover,则该ACK为Full ACK。它响应了进入Fast Recovery之前sender所发送的全部packet,按规定可以退出Fast Recovery阶段。在退出之前,会将cwnd缩减到min(ssthresh, FlightSize+SMSS),以保证网络的守恒。
如果ack_seq<recover,则该ACK为Partial ACK。在Partial Acknowledgement一节中已经讨论过,Partial ACK意味着多包的丢失,因此,NewReno会重传某些packet。与其他方案不同,NewReno并不重传Partial ACK中指明的packet,而是目前未被响应的最小的packet,这样可以保证重传始终是从左到右依次进行,保持连续型。与Reno一样,重传之后,NewReno缩减cwnd。具体的做法是,首先减去Partial ACK所响应的packet的数量,然后加上SMSS。总体上是为了保证Fast Recovery结束时,有ssthresh大小的packet在网络中传输。
由于多包丢失的存在,NewReno针对Partial ACK的处理,仍然不能快速的恢复所有丢失的packet,因此超时会经常发生。当超时发生时,NewReno采取的措施是退出Fast Recovery,并在退出之前将recover的值更新为当前high_seq。