TCP Congestion Control

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP Congestion Control相关的知识,希望对你有一定的参考价值。

参考技术A

rfc5681 详细说明了TCP的四个拥塞控制算法:慢启动、拥塞避免、快速重传和快速恢复。

或者,利用选择性确认 (SACK) 的 TCP 可以利用 SACK 信息来确定何时传入的ACK是“重复”。

慢启动和拥塞避免算法在TCP发送端使用,用于控制进入网络的数据量。

为了实现这两个算法,在TCP的per-connection阶段引入了两个变量:

开始向未知情况的网络进行传输时要求TCP 缓慢探测网络以确定可用带宽 ,从而避免不适当的爆发数据造成网络拥塞。慢启动算法的目标:在 传输开始阶段(采用慢启动算法) 和 重传定时器检测到丢包之后(重启慢启动算法) 避免网络拥塞。另外,慢启动使用"ACK clock"。"ACK clock"在TCP发送端使用,被用于 慢启动、拥塞避免 以及 丢包恢复算法。

cwnd 的初始值 IW 根据 SMSS 的大小而设置

ssthresh 可以设置为任意高度 ,但 ssthresh 在遇到拥塞时必须降低。将 ssthresh 设置尽可能高可以自适应网络条件,而不是一些采用任意的主机限制来决定发送速率。在某些 cases 下,例如系统对网络路径有充分的了解,那么更谨慎地设置 ssthresh 初始值可能有好处。

何时使用慢启动算法、拥塞避免算法

在慢启动期间,TCP的cwnd在每接收到一个新数据的递增确认的ACK后至少增长SMSS个字节。当cwnd的大小超过ssthresh后或当观察到拥塞后 慢启动结束。虽然传统的 TCP 实现会在收到覆盖新数据的 ACK 后精确地通过 SMSS 字节增加 cwnd,但我们建议 TCP 实现增加 cwnd:

其中 N 是在到来的 ACK 中确认的先前未确认的字节数(接收端会采用累积确认、延迟确认等算法,因此存在先前未确认的字节数)。并且不能每个ACK都增加cwnd的大小,毕竟会存在重复的ACK。

在拥塞避免期间,TCP的cwnd在每个往返时间(RTT)增加一个 full-sized segment。拥塞避免算法持续到发生拥塞。在拥塞避免期间增加 cwnd 的基本准则是:

在拥塞避免期间增加 cwnd 的推荐方法是计算新数据的 ACK 已确认的字节数 (同 slow start),但不能每个 RTT 触发的 cwnd 的增长不能超过 SMSS bytes。当确认的字节数达到 cwnd,可以增长 SMSS bytes 。

在拥塞避免期间,TCP可以使用的另一个通用的公式是:

在每个确认新数据的 ACK 到来时执行此调整。该公式为每个 RTT 将 cwnd 增加 1 个 full-sized segment 的基本原理提供了可接受的近似值。

实现说明:

同:

异:

当TCP发送端通过重传定时器检测到 segment loss 且该 segment 尚未通过重传定时器重新发送时, 此时 ssthresh 的值必须重新设置为不超过下列等式中给出的值:

其中,FlightSize 是网络中未完成数据的数量。

另一方面,当TCP发送端通过重传定时器检测到 segment loss 且该 segment 已经通过重传定时器重新发送至少一次时,此时 ssthresh 的值保持不变。

实现说明:

此外,在超时(Retransimission Timer)时,cwnd 必须设置为不超过丢失窗口 LW,LW 等于 1 个 full-sized segment(无论 IW 的值如何)。 因此,在重传 loss segment 后,TCP 发送方使用慢启动算法将窗口从1 个 full-sized segment 增加到新的 ssthresh 值,此后再次使用拥塞避免算法。

超时后基于慢启动的丢失恢复(loss recovery)可能会导致虚假重传,从而触发重复确认。 在 TCP 实现中,对这些重复 ACK 到达的反应差异很大。 本文档没有具体说明如何处理此类确认,但可以指出这是一个可以从额外关注、实验和规范中受益的领域。

当一个乱序的 segment 到达时,TCP的接收端立即发送一个重复的 ACK 。这个 ACK 的目的是通知 发送端:接收端接收到了一个乱序的 segment 以及接收端目前期待收到的序列号。从发送端的视角来看,重复的 ACK 可能会引起一些网络问题。

另外,当TCP 的接收端接收到的 segment 填充空间中全部或部分间隙时,TCP接收端应该立即发送 ACK 。这将为发送方的超时重传、快速重传或高级丢失恢复算法等方法提供更及时的信息。

TCP发送端基于到来的重复ACK,使用快速重传算法来检测和修复丢包。

快速重传算法 :快速重传算法使用3个重复的ACK作为一个segment已丢失的指示,在接收到3个重复的ACK后,TCP重新传输看似丢失的segment,而无需等待重传计时器的触发。

快速恢复算法 :在快速重传算法发送看似丢失的 segment 之后,快速恢复算法控制新数据的传输,直到非重复的ACK到达。

收到重复的ACK不执行慢启动的原因:收到重复的ACK不能完全表明一个 segment 已经丢失,因为该部分 segment 最可能已经离开了网络(segment 在接收端的缓冲区中,不再被视作网络资源)。此外,由于保留了 ACK 的时钟(重传定时器),TCP发送端可以继续传输新的 segments 。

上面描述的 TCP 拥塞控制算法的一个已知问题是:TCP在空闲一段相对长的时间之后,TCP将被允许传输潜在的不适当的流量突发。

[Jac88] 建议 TCP 在相对较长的空闲期后使用慢启动来重新启动传输。 慢启动用于重新启动 ACK 时钟,就像它在传输开始时所做的那样。 该机制已以下列方式广泛部署。 当 TCP 在超过一次重传超时时长后仍未收到一个 segment 时,cwnd 会在传输开始前减小到重新启动窗口 (RW) 的值。

出于本标准的目的,我们定义RW = min(IW,cwnd)。

因此,如果 TCP 在超过重传超时的时间间隔内没有发送数据,则 TCP 应该在开始传输之前将 cwnd 设置为不超过 RW。

[RFC112] 提出的 延迟应答算法 可以应用在TCP的接收端。当然在采用 延迟应答 时,TCP的接收端不必过度延迟应答。

延迟应答的算法:

在某些情况下,发送方和接收方可能无法就什么构成 full-sized segment 达成一致。 如果每次从发送方接收到 2*RMSS 字节的新数据时至少发送一个 ACK,则认为实现符合此要求,其中 RMSS 是接收方指定给发送方的最大段大小(或默认值 536 字节,根据 [RFC1122],如果接收方在连接建立期间未指定 MSS 选项)。

当检测到数据窗口中的第一次丢失时,ssthresh 必须设置为不超过等式 给出的值。 其次,在修复新的数据窗口中的所有 lost segments 之前,每个 RTT 中传输的segments 必须不超过检测到丢失时未完成的segment的数量的一半。 最后,在给定的段窗口中的所有损失

最后,在给定的段窗口中的所有丢失都已成功重传后,cwnd 必须设置为不超过 ssthresh,并且必须使用拥塞避免来进一步增加 cwnd。 在两个连续的数据窗口中丢失,或丢失重传,应被视为拥塞的两个指示,因此,在这种情况下,cwnd(和 ssthresh)必须降低两次。

我们建议 TCP 实施者采用某种形式的高级丢失恢复,可以应对数据窗口中的多个丢失。 [RFC3782] 和 [RFC3517] 中详述的算法符合上述一般原则。 我们注意到,虽然这不是符合上述一般原则的仅有的两种算法,但这两种算法已经过社区审查,目前处于标准轨道上。

本文档要求 TCP 在重传超时和重复确认到达的情况下降低其发送速率。 因此,攻击者可以通过导致数据包或其确认丢失,或者通过伪造过多的重复确认来损害 TCP 连接的性能。

为了响应 [SCWA99] 中概述的 ACK 分割攻击,本文档建议根据每个到达的 ACK 中新确认的字节数而不是每个到达的 ACK 上的特定常量来增加拥塞窗口( cwnd += min (N, SMSS) ,N 是在到来的 ACK 中确认的先前未确认的字节数)。

互联网在很大程度上依赖于这些算法的正确实施,以保持网络稳定性并避免拥塞崩溃。 攻击者可以通过伪造过多的重复确认或对新数据的过多确认,使 TCP 端点在面对拥塞时做出更积极的响应。 可以想象,这样的攻击可能会使网络的一部分陷入拥塞崩溃。

以上是关于TCP Congestion Control的主要内容,如果未能解决你的问题,请参考以下文章