TCP 拥塞控制

ZingLix July 24, 2018

TCP 协议实现可靠传输的核心在于确认重传,而重传意味着消耗更多的资源。然而在一个拥塞到快崩溃的网络中,十分容易发生丢包,而这又会触发重传,从而使得网络条件更加糟糕,为此 TCP 设计了拥塞控制算法。

概述

为了能够控制发送速度,TCP 中有一个 拥塞窗口 变量(congestion window, cwnd),配合滑动窗口中的接收窗口 rwnd,所以网络中发送速度为两者间的较小值。cwnd 值的确定是本文讨论的重点。

IP 层并不提供网络拥塞反馈,所以在 TCP 中一般靠丢包的发生来判断是否发生拥塞,也有一些其他的拥塞探测方法。

慢启动

当一个连接刚建立时,此时目的是尽可能的增大 cwnd,但是并不知道网络状况如何,所以一开始只能以较慢的速度传输,收到确认后可以加快传输速度,直到发生了丢包,说明此时发生了拥塞,这时交由拥塞避免算法。

慢启动中将一个 SMSS(发送方最大段大小)作为一个单位,初始窗口设为 1 个 SMSS,在每次没有出现丢包的 ACK 后翻倍,成指数级增长,直到达到阈值或检测到丢包。如果发生因超时而产生的丢包,cwnd 会置为 1,阈值减半,重新开始慢启动。如果收到三个 ACK,会触发快速重传并进入快恢复状态。

拥塞避免

相比慢启动,拥塞避免增大 cwnd 的机制就没有那么激进,每个 ACK 都只增加一点点

\[cwnd \ += SMSS * \frac{SMSS}{cwnd}\]

可以更直观的看作每个 RTT 窗口加一。发生超时与慢启动处理方式一样,cwnd 置 1,阈值减半。收到三个冗余 ACK,cwnd 减半,阈值减为 cwnd 一半(cwnd = ssthresh = cwnd / 2)。

快速恢复

在收到多个冗余 ACK 时会进入快速恢复状态,触发快速重传机制,对于 cwnd 的处理则有不同。

  • TCP Taho:阈值减为 cwnd 一半,cwnd 置 1,重新开始慢启动。
  • TCP Reno:拥塞窗口和阈值就设为 cwnd 一半,进入快恢复状态,此时重传未确认的包,直到收到一个新的 ACK 退出,转用拥塞避免。
  • TCP NewReno:与 Reno 基本相同,但退出机制不同。它记录进入前发送的最大序号作为恢复点,接收到序列号不小于恢复点的 ACK 时退出。例如已发送 1-100 号报文,此时进入快速恢复状态,则记录恢复点 100,然后重传丢失的报文,直到收到 101 号 ACK 才退出。

状态转换

拥塞避免和慢启动并不能同时使用,一般用一个阈值 ssthresh,当 cwnd 小于 ssthresh 时使用慢启动,大于时使用拥塞避免。初始值一般任意设定。

不同状态对于不同的丢包有不同的处理,从而构成了 TCP 拥塞控制算法的整体。

相关文章