专栏名称: 克里斯朵夫李维
目录
相关文章推荐
今天看啥  ›  专栏  ›  克里斯朵夫李维

TCP的拥塞避免

克里斯朵夫李维  · 掘金  ·  · 2020-01-13 03:02
阅读 22

TCP的拥塞避免

TCP的拥塞避免

在TCP传输数据的时候,发送方的窗口受到网络和接收方窗口的影响,实际上发送方窗口被网络影响的更加严重。

实际的网络环境是非常复杂的,每一跳路由的带宽可能都不一样,如果一下接收到太多的数据网络就会发送拥塞,拥塞的结果就是丢包。导致网络拥塞的数据量称为拥塞点。 拥塞点是一个在不断变化的动态值,TCP需要在尽可能大的发送窗口下,避免触碰到拥塞点。TCP主要使用以下几种算法来避免拥塞的发生:

  • 慢启动算法
  • 拥塞避免算法
  • 快重传算法
  • 快恢复算法

1. 慢启动算法

慢启动算法的思想是为发送方增加了一个拥塞窗口(Congestion Window),记为cwnd。

拥塞窗口指的是在收到对端的ACK时还能发送的最大MSS数。拥塞窗口是发送端维护的一个值,不会像接收方窗口(rwnd)那样通告给对端,发送方窗口的大小是cwnd和rwnd的最小值。目前的linux的拥塞窗口初始值为10个MSS。

慢启动算法,每经过一个RTT,cwnd变为之前的两倍。发送方开始时发送initcwnd个报文段(假设接收方窗口没有限制然后等待ACK。当收到该ACK时,拥塞窗口扩大为initcwnd*2,即可以发送initcwnd*2个报文段。当收到这发出报文段的ACK时,拥塞窗口继续扩大为initcwnd*4,这是一种指数增加的关系。

慢启动算法示意图:

计算公式

指数n为RTT次数。

2.拥塞避免算法

拥塞避免算法和慢启动算法是两个不同的算法,但是他们都是为了解决拥塞,在实际中这两个算法通常是在一起实现的。相比于慢启动算法拥塞避免算法多维护了一个慢启动阈值ssthresh

当cwnd<ssthresh时,拥塞窗口使用慢启动算法,按指数级增长。 当cwnd>ssthresh时,拥塞窗口使用拥塞避免算法,按线性增长。

拥塞避免算法每经过一个RTT,拥塞窗口增加initcwnd

当发生拥塞的时候(超时或者收到重复ack),RFC5681认为此时ssthresh需要置为没有被确认包的一半,但是不小于两个MSS。此外,如果是超时引起的拥塞,则cwnd被置为initcwnd

超时重传对传输性能有严重影响。原因之一是在RTO阶段不能传数据,相当于浪费了一段时间;原因之二是拥塞窗口的急剧减小,相当于接下来传得慢多了。

3.快速重传算法

有时候拥塞比较轻微,只有少量包丢失,后续的包能够正常到达。当后续的包到达接收方时,接收方会发现其Seq号比期望的大,所以它每收到一个包就Ack一次期望的Seq号,以此提醒发送方重传。当发送方收到3个或以上重复确认(Dup Ack)时,就意识到相应的包已经丢了,从而立即重传它。这个过程称为快速重传。

为什么要规定凑满3个呢?这是因为网络包有时会乱序,乱序的包一样会触发重复的Ack,但是为了乱序而重传没有必要。由于一般乱序的距离不会相差太大,比如2号包也许会跑到4号包后面,但不太可能跑到6号包后面,所以限定成3个或以上可以在很大程度上避免因乱序而触发快速重传。

还有一个问题,如下图:

如果2号和3号包都丢失了,但是后面4,5,6,7号都正常收到了,并触发了三次Ack2。在重传了2号包之后该传哪个包那,是全部需要重传还是只传2号包?

为了解决这种问题,TCP在发送重复的Ack包的时候,会告诉接收方收到的已经收到包的序号,如下图:

这样发送方就知道该重传哪个包了,这种方式被称为选择性确认(Selective Acknowledgement)

4.快速恢复

如果在拥塞阶段发生了快速重传就没有必要像超时重传那样处理拥塞窗口了,因为此时的拥塞并不是很严重。RFC5681建议此时的慢启动阈值ssthreh设置为没有被确认包的1/2,但是不小于2个MSS。拥塞窗口设置为慢启动阈值加3个MSS。这个过程被称为快速恢复

总结

超时重传对性能的影响最大,因为在RTO期间不能传输任何数据,而且拥塞窗口会急剧减小。所以应该尽量避免超时重传。

丢包对极小文件的影响比大文件严重,因为小文件可能不能触发三次重复的Ack,导致无法快速重传。

参考

  1. 《Wireshark网络分析就是这么简单之重传的讲究》



原文地址:访问原文地址
快照地址: 访问文章快照