说说 TCP 的拥塞控制?
说说 TCP 的拥塞控制?
什么是拥塞控制?不是有了流量控制吗?
之前提到的流量控制是为了防止发送方的数据填满接收方的缓存,但它并不能感知整个网络的状态。
在计算机网络中,通常是共享的环境,因此可能会出现网络拥塞的情况,这是由于其他主机之间的通信导致的。
当网络出现拥塞时,继续发送大量数据包可能会导致延迟和丢包等问题。TCP协议会重传数据,但每次重传都会增加网络的负担,进而导致更大的延迟和丢包,形成恶性循环。
因此,TCP不能忽略整个网络中发生的情况,它被设计为一种无私的协议,当网络出现拥塞时,TCP会自我牺牲,降低发送的数据量。
这就是拥塞控制的概念,其目的是避免发送方的数据充满整个网络。
可以将其类比为水管,不能让过多的水(数据流)流入水管,如果超过水管的承受能力,水管就会爆裂(丢包)。
发送方会维护一个拥塞窗口(congestion window)的变量,用于调整要发送的数据量。
什么是拥塞窗口?它和发送窗口有什么关系?
拥塞窗口(cwnd)是发送方维护的一个状态变量,它会根据网络的拥塞程度进行动态调整。
发送窗口(swnd)和接收窗口(rwnd)大致相等,而引入拥塞窗口的概念后,发送窗口的大小将变为swnd = min(cwnd, rwnd),即拥塞窗口和接收窗口中的最小值。
拥塞窗口(cwnd)的变化规则如下:
- 如果网络中没有出现拥塞,cwnd会增大;
- 一旦网络出现拥塞,cwnd会减小;
拥塞控制有哪些常用算法?
拥塞控制有几种常用的算法:
- 慢启动(Slow Start)
- 拥塞避免(Congestion Avoidance)
- 拥塞发生(Congestion Occurrence)
- 快速恢复(Fast Recovery)
慢启动算法
慢启动算法的思想是逐渐增加拥塞窗口的大小,以探测网络的拥塞程度。在TCP建立连接后,发送方开始时不会发送大量数据,而是先进行探测。对于每个收到的ACK,拥塞窗口cwnd的大小会增加1(以MSS为单位)。每个轮次中,发送窗口的大小会加倍,呈指数增长。如果没有出现丢包,发送窗口会持续增大;如果出现丢包,拥塞窗口会减半,然后进入拥塞避免阶段。
举个例子:
- 在建立连接后,初始化拥塞窗口cwnd为1,表示可以传输一个MSS大小的数据。
- 每收到一个ACK确认应答,cwnd增加1,因此一次可以发送2个MSS大小的数据。
- 当收到两个ACK确认应答时,cwnd增加2,因此可以比之前多发送2个,一次可以发送4个MSS大小的数据。
- 当这4个ACK确认到来时,每个ACK确认增加1,总共增加4,因此可以比之前多发送4个,一次可以发送8个MSS大小的数据。
可以看到,发送的数据包数量以指数形式增长。
为了防止cwnd增长过大导致网络拥塞,还引入了一个慢启动阈值(ssthresh)状态变量。当cwnd达到该阈值时,会减缓增长速度,进入拥塞避免算法。
拥塞避免算法
一般情况下,慢启动阈值(ssthresh)设为65535字节。当cwnd达到慢启动阈值后:
- 每收到一个ACK时,cwnd = cwnd + 1/cwnd
- 每过一个往返时间(RTT),cwnd = cwnd + 1
可以看出,这是一种线性增长的算法,避免了过快增长导致网络拥塞的问题。
继续上面的慢启动例子,假设ssthresh为8:
- 当收到8个ACK确认应答时,每个确认增加1/8,总共增加1,因此可以发送9个MSS大小的数据,进入线性增长阶段。
拥塞发生
当网络发生拥塞导致丢包时,会出现两种情况:
- 超时重传(RTO Timeout)
- 快速重传(Fast Retransmit)
对于超时重传,会采用拥塞发生算法:
- 慢启动阈值ssthresh = cwnd/2
- cwnd重置为1
- 进入新的慢启动过程
这种方式就像是高速驶入紧急刹车,然后急速倒车,有点不太优雅...
其实有更好的处理方式,即快速重传(Fast Retransmit)。当发送方收到3个连续的重复ACK时,会快速重传,而不必等待RTO超时再重传。
在快速重传发生后的拥塞发生算法中:
- 拥塞窗口大小cwnd = cwnd/2
- 慢启动阈值ssthresh = cwnd
- 进入快速恢复算法
快速恢复
快速重传和快速恢复算法通常同时使用。快速恢复算法认为,收到3个重复的ACK说明网络并不是很糟糕,所以不必像RTO超时那样强烈地回退。
在快速重传后,cwnd和ssthresh已经被更新为:
- cwnd = cwnd/2
- ssthresh = cwnd
然后进入快速恢复算法:
- cwnd = ssthresh + 3
- 重传丢失的那几个数据包(对应重复的ACK)
- 如果再收到重复的ACK,cwnd = cwnd + 1
- 如果收到新数据的ACK,cwnd = ssthresh。因为收到新数据的ACK表示恢复过程已经结束,可以重新进入拥塞避免算法。