RFC2001

本文是对RFC2001的翻译。


0. RFC2001   TCP Slow Start, Congestion Avoidance, Fast Retransmit, and Fast Recovery Algorithms

    现代TCP的实现包含了四个相互交织的算法,但它们还从未被完整收录到一个互联网标准文件中过,它们分别是:慢启动(slow start)、拥塞避免(congestion avoidance)、快速重传(fast retransmit)、快速恢复(fast recovery)。其实,最早在RFC1122中就已经要求TCP必须实现慢启动和拥塞避免(Section 4.2.2.15),后来又增加了对快速重传和快速恢复机制的要求。RFC2001就是将这四种算法组织起来了。

1. Slow Start

    老的TCP实现在连接开始时,会一股脑的将接收方所宣称的窗口大小的报文段(segments)全部塞到网络中,当两台主机在相同的局域网(LAN) 时,这种方法还是可以接受的。但是一旦在中间插入了路由器或者慢速链路,问题就产生了。一些中间媒介(如:路由器)会对数据包进行排队缓存,并引发内存空间不足的问题,这会极大的降低TCP连接的吞吐率

    慢启动就是用来避免这种情况的算法,它是通过观察对端应答ACK的速率来控制本端的发送速率而实现的

    慢启动为发送方TCP增加了一个额外的窗口:拥塞窗口,cwnd。当与另一个网络中的一台主机建立连接后,拥塞窗口被初始化为一个报文段(one segment)(报文段大小是由对端声明,或默认的,典型大小为536 or 512)。每当收到一个ACK,拥塞窗口就增加一个报文段。发送者可以发送的总数据量由拥塞窗口和接收窗口(advertised window)两者之间的较小者确定。拥塞窗口是由发送者来承担的流控机制,而接收窗口则是由接收者来承担的流控机制。前者建立在发送方对网络拥塞状况的评估的基础上,而后者则依赖于接收方的可用缓冲区空间大小。

    发送方先发送一个报文段,然后等待ACK。当收到ACK后,拥塞窗口由1增加到2,此时就可以发送2个报文段出去。当这两个报文段的ACK也分别到达后, 拥塞窗口就增加到了4。尽管由于接收方会延迟发送ACK,比如每收到两个报文段发送一个ACK,它还不能称为一种严格意义上精确的指数形式,但它还是提供了一种指数级的增长。

    在某个点上会达到网络容量的上限,中间路由器开始丢包,这就相当于通知发送方它的拥塞窗口太大了。

    早期的时候,只有当连接的对端不在同一个网络时,才会执行慢启动流程。而现在的实现则总是执行慢启动。


2. Congestion Aoidance

    拥塞可能发生在数据由一根粗管道(a fast LAN)流向一根细管道(a slower WAN)时,也可能发生在多个输入流到达一台路由器,而这台路由器的输出能力低于所有输入之和的时候。拥塞避免是一种处理丢包的方法。

    这个算法建立在“由数据包损坏所造成的丢包比例非常低(低于1%)“的假设之上,因此,丢包就可以被看作是网络中的某处发生了拥塞的信号。丢包由两类事件所标识:1)发生了超时;2)接收到重复的ACK。

    拥塞避免和慢启动是具有不同目的两个独立算法,但是当拥塞发生时,TCP必须降低传输的速度,并且启用慢启动流程使一切重新开始。在实际中,这两者是在一起实现的。

    拥塞避免和慢启动要求每条连接维护两个变量:1)一个拥塞窗口,cwnd;2)一个慢启动阈值,ssthresh;相互结合后的算法操作如下:

    1. 对于一个给定的连接,初始时设置cwnd为一个数据段(segment),ssthresh为65535 bytes;

    2. TCP的发送方法永远也不会发送超过minimum[cwnd,接收方的advertised window] (指cwnd 和 接收窗口之间的较小者)量值的数据;

    3. 当拥塞发生时(超时或收到重复ACK),将当前窗口值的一半(指cwnd和接收窗口之中的较小者,但至少保留2个数据段的大小)存入ssthresh中。如果拥塞是通过超时所标识的,还要将cwnd重置为一个报文段大小(就像进入慢启动流程一样);

    4. 当有新的数据被对端应答时,增加cwnd,增加的方式依赖于TCP是正在执行慢启动还是拥塞避免;

        如果cwnd的值小于等于ssthresh,说明TCP正处在慢启动阶段,否则处于拥塞避免阶段。慢启动过程在到达上次拥塞发生的位置之前结束(因为在步骤2中已经记录了引发拥塞的窗口大小的一半),然后进入拥塞避免阶段;

        慢启动开始时cwnd的大小为一个数据段,并且每收到一个ACK就增加一个段大小。正如前所述,这将以指数形式开放窗口:发送一个段、然后两个、然后四个,等等。拥塞避免则要求每次收到一个ACK,cwnd增加 segsize*segsize/cwnd的大小,其中segsize是段大小,且cwnd是以字节数维护的。与慢启动阶段的指数形式增长相比,这是一种线性增长。cwnd在每个round-trip time内最多增加一个数据段的大小(不考虑在一个RTT内会收到多少个ACK),与之相反的是,慢启动则是通过一个round-trip time内收到的ACK数量来增加cwnd的。

    在拥塞避免阶段,许多不正确的实现每次会增加段大小的一部分(典型的是段大小的八分之一)。这个错误在未来实现中不应该再继续被作为参照。

    译:这里这样说是因为在上一段中提到,拥塞避免阶段的cwnd在每个round-trip time中增加一个数据段的大小。


3. Fast Retransmit

    修改拥塞避免算法的提议在1990年被提出,在描述这个改变之前,需要认识到在接收到失序的报文段时TCP可能会产生一个立即的应答(一个重复的ACK)(RFC1122 4.2.2.21节说明这么做的一个原因是为了实验快速重传算法)。这个重复的ACK不应该被延迟,它的目的是为了让对端了解到有一个报文段被乱序接收,并且将期望接收的数据段的序列号告知。

    由于TCP并不清楚一个重复的ACK是由报文丢失还是失序引发的,它假设如果是由失序引发的,那么在失序问题被解决之前,应该只有一到两的重复的ACK,并且随后就会产生新的ACK。如果收到三个或以上的重复ACK,那么就很有可能表明有报文已经丢失了,TCP会立即针对丢失的报文段执行重传,而不必等待重传定时器到期。


4. Fast Recovery

    当快速重传机制发送出疑似丢失的报文段之后,执行拥塞避免,但无需重新进入慢启动流程,这就是快速恢复算法。它是为了在适度拥塞的情况下保持高吞吐率所做的改进,尤其是对大窗口的情况。

    在这种情况下不执行慢启动流程的原因是重复ACK的接收会通知TCP有超过一个的报文已经丢失了。接收方在收到其他报文段时只会产生重复ACK,但这个报文段会被放入接收缓冲区中,也就是说此时在两端之间仍有数据流动,TCP不想进入慢启动流程从而导致流量猛然下降。

    快速重传和快速恢复算法通常按如下的方式一起实现:

    1. 当一条连接上收到第三个重复ACK时,设置ssthresh为当前拥塞窗口cwnd大小的一半,但是不少于两个段。重传丢失的报文段。将cwnd设为ssthresh加上3倍的段大小。它是根据已经离开网络并由另一端所缓存的报文段数量对拥塞窗口的大小进行了放宽(3);

    译注:TCP在收到失序报文段时会立即触发重复ACK,收到三个重复ACK就说明对端接收并缓存了三个失序段,这就是所说的“放宽“(inflates);

    2. 每再收到一个重复ACK,就对cwnd增加一个段大小。这相当于针对每个被对端所缓存的报文段都对拥塞窗口进行了放宽。并在新的cwnd值允许的条件下,传输一个报文;

    译注:与上一条一样,每收到一个重复ACK都意味着对端收到并缓存了一个新的失序报文段,同时也意味着这些报文段已经离开网络,进入对端系统中,因此可以据此对拥塞窗口进行适当放宽。

    3. 当下一个新数据的应答ACK到达时,将cwnd设置为ssthresh(在步骤1中设定)。这个ACK应该是对步骤1中重传数据的应答。此外,这个ACK还应该是对从丢失的报文开始到收到第一个重复ACK之前发送的报文之间所有发送数据的应答。这一步是拥塞避免,因为TCP已经将速度降低至丢失发生时的一半。

    快速重传算法首先出现的4.3BSD Tahoe发行版中,紧随其后的是慢启动,快速恢复算法出现在BSD 4.3Reno发行版中。


5. Security Considerations

    本备忘录中不讨论安全相关内容。




你可能感兴趣的:(RFC2001)