TCP的拥塞控制
网络拥塞的原因与危害
网络拥塞(congestion control)是由发送方的发送速率(transmission rate)过高引起的,会导致网络资源没有被充分利用,影响带宽和延时性能
我们假设有这样一种场景:有两台主机A和B,它们分别与目标主机创建了TCP连接,A和B的传输路径上共享了一个路由器,A和B都以v bytes/s的速率发数据,数据包到达该路由器后,通过同一个链路(outgoing link)转发到目标主机,该链路的最大容量为R。路由器的链路以最大容量在传输数据时,如果路由器还收到新的包,会将其缓存在路由器中。
基于上述场景,有以下情况会引起A的发送速率过高,从而引起网络拥塞:
- 随着A主机发送速率接近R/2的链路容量,进入路由器缓存队列的数据包也会越来越多,数据包的排队延时越长。
- 当路由器缓存满了,新到达的数据包会被丢弃,此时发送方会超时重传,会引起实际带宽的下降,大概会下降至R/3。
- 当A的超时时间设置的太短,会引起不必要的重传(路由器排队队列中的包和重传的包都到达了目标主机),从而进一步降低了网络带宽。
- 在更复杂的场景中,所有主机都以满速率发数据时,每个主机占用了离它更近的路由器的全部缓存队列,其它主机的数据包会被路由丢弃永远无法送达目标主机,浪费了所有上游链路路由器的带宽资源。
流量控制是避免发送方的数据填满接收方的缓存,但是并不知道网络中发生了什么。拥塞控制的目的是避免发送方的数据填满整个网络。为了在发送方调节所要发送数据的量,定义了一个叫做拥塞窗口的概念。
TCP拥塞控制算法
TCP使用的是端到端的拥塞控制,不依靠网络层进行辅助,IP层不向端系统提供显式的网络拥塞反馈。发送方根据所感知到的网络拥塞程度来限制发送速率,如果发送方感知从它到目的地之间的路径上没什么拥塞,则TCP发送方增加发送速率,反之降低发送速率。
首先,需要定义发送方如何感知它与目标主机之间的路径上出现了拥塞:超时或收到来自接收方的3个冗余ACK。
随后,当发送方感知到拥塞后,需要限制发送速率,这是通过在发送方维护一个拥塞窗口(cwnd)实现的。在发送方中未被确认的数据量不会超过cwnd与rwnd中的最小值,即:
1 | LastByteSent - LastByteAcked <= min(cwnd, rwnd) |
当发送方收到来自接收方的ACK,会增加cwnd,加速发送速率,反之减少cwnd。
慢启动(slow start)
在TCP连接建立的一开始,cwnd
的值被初始化为MSS,因此发送速率为MSS/RTT,此外还设置了ssthresh
参数。在慢启动阶段,TCP协议主要工作是找到最大可用的发送速率,每收到第一个ACK,cwnd += MSS
。因此,如果一切顺利的话,每经过一个RTT,cwnd翻一翻,按照指数级增长。
但是发送速率无法持续增加,在以下几种情况下会发生状态转移:
当遇到超时事件时,TCP将cwnd重置为1 MSS,并将
ssthresh = cwnd/2
。当收到3个冗余ACK,TCP执行快速重传,并进入快速恢复状态。
当
cwnd >= ssthresh
时,结束慢启动,并进入到拥塞避免状态。
拥塞避免
在拥塞避免状态,TCP会更加谨慎地增加cwnd,因为进入拥塞避免状态意味着cwnd的值大约是上次遇到拥塞时的值的一半,距离拥塞也不远了。此时,每个RTT只将cwnd的值增加一个MSS,而不是翻一倍。
此时如果遇到超时事件,cwnd的值被重置为1个MSS,ssthresh = cwnd/2
,回到慢启动状态。
如果碰到3到冗余ACK,说明网络状况没有那么差,TCP将cwnd = cwnd/2+3MSS
,ssthresh = cwnd/2
,并进入到快速恢复状态。
快速恢复
快速恢复状态仍然以线性的速度增长cwnd,直至到达ssthresh阈值,进入拥塞避免状态。
其它拥塞控制算法
在Infiniband协议中,采用明确的拥塞通告机制,网络层设备会明确地在网络层数据头中添加拥塞信息,接收方在ACK报文中设置ECN比特,发送方在下一次发送报文中设置ECE,并减半cwnd。