front-end-pigs / blog

博客
2 stars 0 forks source link

TCP-IP详解: 慢启动和拥塞控制 #34

Open jangdelong opened 4 years ago

jangdelong commented 4 years ago

在网络实际的传输过程中,会出现拥塞的现象,网络上充斥着非常多的数据包,但是却不能按时被传送,形成网络拥塞,其实就是和平时的堵车一个性质了。TCP设计中也考虑到这一点,使用了一些算法来检测网络拥塞现象,如果拥塞产生,变会调整发送策略,减少数据包的发送来缓解网络的压力。

拥塞控制主要有四个算法:

  1. 慢启动

  2. 拥塞避免

  3. 拥塞发生时,快速重传

  4. 快速恢复

慢启动算法

之前介绍的滑动窗口能够让协议栈同时发送多个报文段,这样可以提高网络通信的效率,对于一些处理能力不佳的中间路由器,很可能会导致存储被耗尽的状况,从而严重降低了TCP连接的吞吐量,不断的重传. 非常的可怕, 介于此,引入了慢启动这个算法。

慢启动为发送方的TCP增加了一个窗口:拥塞窗口,记为cwnd,初始化之后慢慢增加这个cwnd的值来提升速度。同时也引入了ssthresh门限值,如果cwnd达到这个值会让cwnd的增长变得平滑,算法如下

  1. 连接建好的开始先初始化cwnd = 1,表明可以传一个MSS大小的数据

  2. 每当收到一个ACK,cwnd++; 呈线性上升

  3. 每当过了一个RTT,cwnd = cwnd*2; 呈指数让升

  4. 当cwnd >= ssthresh时,就会进入“拥塞避免算法”

拥塞避免算法

从慢启动可以看到,cwnd可以比较快的增长,但是不能一直无限增长,需要某个限制,TCP使用了ssthresh的变量,当cwnd超过这个值后,慢启动过程结束,进入拥塞避免阶段。拥塞避免的主要思想是加法增大,也就是让cwnd的值线性增加,此时当窗口中所有的报文段都被确认是,cwnd的大小才加1,cwnd的值随着RTT线性增加,这样就可以避免增长过快导致网络拥塞,慢慢的增加到网络的最佳值。 算法:

  1. 收到一个ACK时,cwnd = cwnd + 1/cwnd

  2. 当每过一个RTT时,cwnd = cwnd + 1

图示

结合图来看下数据发送过程中慢启动和拥塞避免算法的使用情况

image

  1. 连接建立,开始传输数据,cwnd = 1 , ssthresh的初始值为16,发送第一个包

  2. 发送端收到一个确认后,cwnd加1,于是可以 发送2个数据包

  3. 收到2个ACK之后,这个时候cwnd + 2 , 于是可以发送4个数据包

  4. 收到4个ACK后,这个时候cwnd + 4 ,于是可以发送8个数据包, 可以看到这个时间段,cwnd随着传输轮次的增长,成指数增长

  5. 当拥塞的窗口达到ssthresh后,慢启动算法结束,开始进入拥塞避免算法

  6. cwnd按照一个RTT进行+1的线性增加,假设到达24时,出现网络拥塞

  7. ssthresh = 1/2 * cwnd = 12, cwnd = 1 继续重新执行慢启动算法

  8. 同样当cwnd = 12时 执行拥塞避免算法

其中第7步属于对网络拥塞的一种处理, 什么状态下才会认为是拥塞? 基本上就认为是有丢包产生,在前面知道丢包产生会有2中处理方法超时重传和快速重传,其中如果RTO超时的时候,TCP认为环境已经很糟糕了,

  1. sshthresh = cwnd /2

  2. cwnd 重置为 1

  3. 进入慢启动过程

如果是快速重传,则:

TCP Tahoe的实现和RTO超时一样。

TCP Reno的实现是:

  1. cwnd = cwnd /2

  2. sshthresh = cwnd

  3. 进入快速恢复算法——Fast Recovery

简单的来说,发送的速率总是在不断的增长,只不过一开始增长比较快,指数增长,到达门限值的时候,切换增长模式,变成线性增长,当系统中出现了丢包重传现象,判断已经网络已经发送阻塞,要重新设定参数,进入慢启动状态。

快速重传

在TCP报文段丢失或者接收端收到乱序的TCP报文段等情况下,发送端都会收到重复的确认报文段。

当发送端连续收到3个重复的确认报文端段的时候,tcp就认为拥塞发生了。然后会立即重传丢失的报文段。

这就是快速重传的机制。

快速恢复

快速恢复机制一般和快速重传机制同时使用。快速恢复机制如下:

  1. 当发送端收到第三个重复确认的报文时,会更新ssthresh的值,然后立即重传丢失的报文段,并且设置:cwnd = ssthresh+3*SMSS,进入拥塞避免阶段。
  2. 当收到一个重复确认的报文时,设置cwnd = cwnd +SMSS。此时发送端可以发送新的TCP报文(如果新的cwnd允许)。
  3. 当收到新数据的确认时,设置cwnd=ssthresh。进入拥塞避免阶段。

这里的新数据表示新的报文,而不是丢失的报文。

在旧的tcp拥塞控制算法中,快速重传之后会进入慢启动阶段,而新的tcp拥塞控制算法在快速重传之后进入快速恢复阶段。

如下图:

image

参考

  1. TCP-IP详解: 慢启动和拥塞控制

  2. 浅谈TCP拥塞控制:慢启动和拥塞避免、快速重传和快速恢复