4.4 快速重传和快速恢复 --- TCP Reno
Last updated
Last updated
目前为止描述的拥塞控制机制都来自于最初的 TCP 拥塞控制算法。它们统一被称作 TCP Tahoe,因为它们包含在 1988 年的 4.3 BSD Unix 的 Tahoe 发行版中。在 Tahoe 被广泛部署之后,暴露了这一版TCP的一些问题,并随后在 1990 年代早期的TCP Reno(随着 4.3BSD-Reno 发布)中得以解决。这一节描述 Tahoe 遇到的问题,以及 Reno 的解决方法。
所谓的问题是:由于TCP 超时时间的不精确,导致 TCP 在等待超时的过程中,有很长一段时间连接都“死掉”(注,不发送任何数据)。
一种启发式算法,称为快速重传(fast retransmit),有时可以比常规的超时机制更快的触发丢包重传。快速重传并不是替代常规的超时机制,它只是增加一种可以更快探测丢包的方式,所以实际中,快速重传和超时重传会同时存在于TCP的实现中。
快速重传的核心思想是,每当 TCP 接收端收到一个数据包,它都回复一个 ACK。当一个packet的前序数据还未完全到达时,TCP接收端不能确认该packet的数据,但是它可以再次确认NextByteExpected
(注,详见2.2)。
第二次发送的,具有相同Acknowledgement值的 ACK, 被称为重复 ACK(duplicate ACK)。当发送端看到了一个重复 ACK,它就知道接收端必然收到了一个非顺序到达的包,并且之前的包可能已经被丢弃了。
当然之前的包也可能只是被耽误,而不是被丢弃,所以发送端会等待直到看到足够多的重复 ACK(实际中 是3 个),再来决定当前是真的发生了丢包,进而重传数据。实际中,没有任何丢包的乱序传输也会导致重复ACK。但是快速重传的假设是(也经受了实际的验证),包的乱序传输比丢包要少的多,所以3个重复ACK就可以认为是丢包了。
图 26 展示了重复 ACK 是如何触发快速重传的。在这个例子里,接收端收到了 packet 1 和 2,但是 packet 3被网络丢弃了。因此接收端在收到 packet 4,5,6 时,会回复针对 packet 2 的重复 ACK(为了简化这里的描述,我们这里基于 packet1,2,3 描述,而不是基于序列号描述)。当发送端看到了针对 packet 2 的第三个重复 ACK,也就是 packet 6 触发的,它会重传 packet 3。这里注意的是,当重传的packet 3到达接收端时,接收端会发送一个累积的 ACK 来确认包括 packet 6在内的所有收到的数据。
图 27 展示了带有快速重传机制的 TCP 的行为。将之与图 25 --- 不包含快速重传,进行对比可以发现,拥塞窗口长时间保持水平,并且没有 packet 发送的过程被消除了(注,也就是图25中的4-5.5秒,6.5-8秒之间)。
总的来说,在一个典型的 TCP 连接中,快速重传在超过一半的超时重传之前生效,并取代它作为丢包的触发机制。这样可以带来大概 20% 的吞吐提升。但需要注意的是,快速重传并不能完全取代超时重传。
如果当发生丢包时,EffectiveWindow
已经很小,将不会有足够的后续packet来触发重复ACK。例如,窗口大小只有3个packet,那第1个packet丢弃了,后两个packet也只能产生2个重复ACK。
如果丢包太多,例如在初始的慢启动阶段,滑动窗口算法最终会阻塞发送方,直到发生超时(注,图27中的1.4-2秒之间)。实际中,TCP的快速重传机制可以在每个窗口中最多探测3个丢包。
相比于最初的TCP Tahoe,这里还有一个地方可以提升。当快速重传发生时,表明网络正在拥塞,与其说将拥塞窗口缩减至1个packet然后重新开始慢启动,不如直接从当前拥塞窗口值的一半开始对拥塞窗口进行加法递增。这样就可以消除丢包之后本应该有的慢启动过程,这个机制被称为快速恢复(fast recovery)。
这里背后的逻辑是:既然快速重传能被触发,那么只是偶尔1-2个包丢了,因为至少后面的包还是能送到接收端并触发重复ACK。相比于超时重传,快速重传面临的网络没那么糟糕,所以也就没必要拥塞窗口从1个packet开始慢启动,那就直接从CongestionThreshold
开始加法递增。
实际中,快速恢复一般与快速重传配合使用。同样的快速恢复并不是要取代TCP Tahoe中的机制,更多的还是作为一个补充机制存在。原有的超时之后,CongestionWindow变成1个packet大小的机制还是存在。