TCP流量控制与拥塞控制

我们都知道在网络中,数据是通过数据包来传输的,而TCP是一个连接可靠的协议,会对数据包的发送接收做确认。 在这样的基础上,为了保证TCP运行的效率,也应运而生了相对应的控制策略。

首先我们了解两个基本知识:

MSS:Maximum Segment Size,TCP一次传输发送的最大数据段长度。日常网络中一般为1500,即1500字节。
RTT:Round-Trip Time,往返时延,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。

很明显,在处理大量数据时,数据会被分为很多包被发送,假设我们要发送1000包,那如何选择这1000包的发送方式就是一个非常关键的问题。如果发送的速率过小,网络带宽资源会被浪费,效率低下;如果发送的速率过高,网络带宽可能不足,接收方也有可能没有那么强的接收能力,都会导致数据包丢失。

为了解决这些效率问题,便引入了这两种控制策略。其中流量控制主要处理端到端之间的通信过程,解决接受方的接收能力问题;拥塞控制处理发送方和网络带宽资源的问题,解决网络资源利用率的问题。二者是相辅相成的。

流量控制

TCP使用端到端流量控制协议来避免发送方发送数据太快,以致TCP接收方不能可靠地接收和处理数据。

TCP的流量控制是由大小可变的滑动窗口来实现的,滑动窗口控制流量取决于接收方的窗口大小。

在TCP头部中,有一个16位的窗口字段,用以协定发送时的窗口大小。实际上,TCP的发送与接收双方都会维护一个窗口: 通告接收窗口(rwnd):预防应用程序发送的数据超过对方的缓冲区,接收方使用的流量控制。 拥塞窗口(cwnd):预防应用程序发送的数据超过了网络所能承载的能力。发送方使用的流量控制。 而发送窗口就是取自于上面两者的较小值

p13.png

如图所示就是一个简单的滑动窗口,只有窗口内的数据包才可以被发送,接收到已发送包的确认后,窗口便会向前滑动。因此滑动窗口也是建立与确认重传机制之上的。

拥塞控制

拥塞控制是根据实时探测到的当前网络状态来决定接下来的发送速率的。

Reno

Reno是大家最熟悉、最常用的的拥塞控制算法,也是Linux内核的默认算法。 其主要包括我们所耳熟能详的四个阶段:慢启动、拥塞避免、快速重传、快速恢复

p15.png

先解释一下图片: 横轴是时间推移,也可以理解为发送的轮次,每次发送完一个发送窗口的数据包认为是一轮次 纵轴是拥塞窗口,上面有提到过 slow start:慢启动 congestion avoidance:拥塞避免 ssthresh:慢启动临界值 TD(Triple duplicate acknowledgements):收到三个重复的ACK包 TO(Timeout):超时

慢启动

慢启动过程主要是维护这个拥塞窗口(cwnd)。拥塞窗口是决定发送窗口大小的因素之一,连接建立的时候,cwnd会被初始化为一个比较小的值,一般是2-4个MSS。

在没有出现丢包时每收到一个 ACK 就将拥塞窗口大小增加一个MSS,此时如果发送窗口大小是由cwnd决定的话,那么每轮发送窗口发送完毕,cwnd就会增加一个发送窗口的大小,也就是翻一倍,呈指数增长。通过这种增长方式逐步扩大发送窗口。

拥塞避免

慢启动过程还会维护一个ssthresh阈值,一般是65535字节,即窗口最大值。当cwnd值增长到大于ssthresh时,则将进入拥塞避免阶段。

拥塞避免过程中,无论一个RTT可以收到多少个ACK,每一个RTT时间内都只新增1个MSS,呈线性增长。这样可以减缓触碰拥塞的速度。

超时重传

随着上述两种方式逐渐增大发送窗口,最终肯定会触发拥塞。而触发拥塞一般有两种形式:

TO:出现发送超时,即TCP重传定时器溢出 在出现发送超时后,便会进入超时重传。进入超时重传后,RFC建议将cwnd设置为1个MSS,而对于ssthresh,RFC5681建议的是发生拥塞时未被ACK的数据量(也就是发送窗口)的1/2,但必须大于等于2个MSS。然后再重新执行慢启动过程。

快速重传与快速恢复

另一种触发拥塞的常见形式:

TD:在超时前收到三个重复的冗余ACK数据包,认为是数据包丢失,进入快速重传和快速恢复 丢包的情况可能有两种:的确是网络出现了拥塞或者包序号校验出现问题。如果对于出现拥塞的情况,进行超时重传处理是无可厚非的。但如果还能收到传来的ACK确认包,仅仅是包内容或校验出错,就进入慢启动,是很影响网络效率的。 因此TCP提出了快速重传与快速恢复:

快重传算法要求接收方每收到一个失序的报文段后就立即发出重复确认,而不要等到自己发送数据时才进行捎带确认。而发送方只要一连收到3个同样的确认报文就应当立即重传数据报,不必等待报文段的重传计时器到期。

快速重传之后便会进入快速恢复阶段,将慢启动阈值ssthresh同样修改为当前拥塞窗口值的一半,但拥塞窗口值等于慢启动阈值,在此基础上直接进入拥塞避免阶段。也就是所谓的“乘法减小,加法增大”

为什么是三个重复ACK呢? 首先要说明的是,并不是说三个重复ACK就一定是丢包,乱序和丢包都会造成重复ACK。只是重复ACK数量越多,越有可能是丢包。我们认为数据包发送速度在不出现网络拥塞丢包时是足够快的,而乱序包会被接收方重新排序。经过多个timeout时间后接收方无法完成乱序重排的概率是非常低的,那么ACK越多乱序的情况就是越低的。另一方面,等待多个ACK再启动快速重传也是不现实的,会降低快速重传的效率。而之所以选择三个冗余ACK,RFC也没有给出明确原因,想必也是经过实践得出的经验。

其他拥塞控制协议

  • 基于丢包的拥塞控制:将丢包视为出现拥塞,采取缓慢探测的方式,逐渐增大拥塞窗口,当出现丢包时,将拥塞窗口减小,如 Reno、Cubic 等。
  • 基于时延的拥塞控制:将时延增加视为出现拥塞,延时增加时增大拥塞窗口,延时减小时减小拥塞窗口,如 Vegas、FastTCP 等。
  • 基于链路容量的拥塞控制:实时测量网络带宽和时延,认为网络上报文总量大于带宽时延乘积时出现了拥塞,如 BBR。
  • 基于学习的拥塞控制:没有特定的拥塞信号,而是借助评价函数,基于训练数据,使用机器学习的方法形成一个控制策略,如 Remy。

参考链接

TCP拥塞控制和TCP流量控制

TCP流量控制和拥塞控制

面试头条你需要懂的 TCP 拥塞控制原理


2513 Words

2019-10-05 08:00 +0800