TCP/IP学习笔记:TCP拥塞控制

简介

拥塞指的是

在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏。这种情况就叫拥塞(congestion)。

TCP模块任务:提供网络利用率,降低丢包率,保证网络资源对每条数据的公平性。---- 拥塞控制

标准文档:RFC 5681,介绍了拥塞控制4个部分:慢启动(slow start)、拥塞避免(congestion avoidance)、快速重传(fast retransmit)和快恢复(fast recovery)。

拥塞控制for linux算法实现,有多种:reno算法、vegas算法、cubic算法等。部分或全部实现。
查看方式(for Ubuntu 14):

$ cat /proc/sys/net/ipv4/tcp_congestion_control
cubic

我的PC是采用cubic算法。


术语介绍

拥塞控制最终受控变量:发送窗口(SWND,Send Window)。也就是说,拥塞控制算法最终是通过控制SWND大小,来进行拥塞控制的。

发送窗口

在发送端发送缓存,存在4种类型数据,其中,发送窗口SWND是指(2)和(3)

(1)已经发送并且对端确认(Sent/ACKed)---------------发送窗外 缓冲区外
(2)已经发送但未收到确认数据(Sent/UnACKed)----------发送窗内 缓冲区内
(3)允许发送但尚未发送的数据(Unsent/Inside)---------发送窗内 缓冲区内
(4)未发送暂不允许(Unsent/Outside)-----------------发送窗外 缓冲区内

发送缓存4种类别数据的示意图

接收窗口

接收窗口 指的是TCP报文头窗口字段,用于告诉发送端自己当前接收缓存大小。

发送者最大段大小 SMSS

MSS(Maximum Segment Size) TCP最大报文段长度(RFC 879),指的是每一个TCP报文段中的数据字段的最大长度。

TCP报文段 = 数据字段 + TCP首部(20~40Byte)
MSS = MTU - sizeof(TCPHDR) + sizeof(IPHDR)

MTU:最大传输单元(含TCP头部、IP头部);TCPHDR:TCP报文头;IPHDR:IP报文头。

MSS与MTU含义见下图:

发送者最大段大小,称为SMSS(Sender Maximum Segment Size)。

如何通告MSS?
MSS的默认值是536byte,因此对端应能接受报文段长度是536 + 20(TCP固定首部) = 556byte的TCP报文。如果想要改变MSS,就需要在TCP连接时,通过TCP报文头可变长的选项(option)字段(1byte类型+1byte长度+不定长内容),告知对端。
注意:MSS是设置好值后,再通告对方,而非与对方协商。

SWND大小的影响

如果SWND太小,会引起明显的网络延迟;反之,如果SWND太大,则容易导致网络拥塞。

既然接收窗口RWND可以控制发送窗口,为何还需要拥塞控制,而不直接用接收窗口进行控制?
虽然接收方可以通过接收通告窗口(RWND),来控制发送端SWND。但是接收方并不知道网络拥塞情况,无法针对网络情况进行控制。因此,发送端引入了一个称为拥塞窗口的(Congestion Windo, CWND)的状态变量。实际的SWND值是RWND和CWND中较小者。


慢启动和拥塞避免

慢启动

TCP连接建立OK后,CWND初值IW(Initial Window),大小2~4SMSS -- 发送端最多能发送IW bytes数据。
此后,发送端每收到接收端的一个确认,其CWND就按下式增加:

CWND += min(N, SMSS), 其中,N是此次确认中包含的之前未被确认的字节数   (1) 

这样,CWND将按指数形式扩大,这就是慢启动。
慢启动算法理由:TCP模块刚开始发送数据时,并不知道网络的实际情况,需要一种试探的方式平滑地增加CWND的大小。

慢启动门限

如果不施加其他手段,慢启动必然使得CWND很快膨胀(慢启动并不慢),并最终导致网络拥塞。而慢启动门限(slow start threadhold size, ssthresh),就是这样一个限制:

当cwnd < ssthresh时,使用慢开始算法;
当cwnd > ssthresh时,停止慢开始算法,改用拥塞避免算法;
当cwnd = ssthresh时,既可以用慢开始算法,也可以用拥塞避免算法;

ssthresh初始值16。只要判断出现拥塞时,慢开始门限设为出现拥塞时发送窗口swnd的一半(但不能<2),然后把拥塞窗口cwnd重新设为1,执行慢开始算法。
目的:迅速减少主机发送到网络中的分组数,使得发生拥塞时路由器有足够时间把队列中积压的分组处理完毕。

拥塞避免算法

CWND按线性方式增加,从而减缓其扩大。RFC 5681提到2种实现方式:
1)每个RTT时间内,按(1)式计算新的CWND,而不论该RTT时间内发送端收到多少个确认。
2)每收到一对新数据的确认报文段,就按式(2)来更新CWND。

CWND += SMSS * SMSS / CWND                                        (2)

下图粗略地描述了慢启动和拥塞避免发生的时机和区别。此外,我们假设当前ssthresh = 16SMSS大小(实际远不止这么大)

慢启动和拥塞避免,都是发送端在未检测到拥塞时,所采用的积极拥塞避免的方法。下面介绍拥塞发生时(可能发生在慢启动阶段或拥塞避免阶段)拥塞控制的行为。

发送端如何判断拥塞发生?

  • 传输超时,或者说TCP重传定时器溢出; ---- 拥塞避免
  • 接收到连续3个重复的确认报文; ---- 快速重传,快速恢复

拥塞控制对这两种情况有不同的处理方式。第一种情况,仍然使用慢启动和拥塞避免;第二种情况,则使用快速重传和快速回复(如果真的发生拥塞)。

如果发送端检测到拥塞发生是由于传输超时,即上述第一种情况,那么它将执行重传并做如下调整:

ssthresh = max(FlightSize / 2, 2 * SMSS)             (3)
CWMD <= SMSS

其中,FlightSize是已经发送但未收到确认的字节数。这样调整后,CWMD将小于SMSS,那么必然小于新的慢启动门限值ssthresh(根据式(3),ssthresh一定不小于SMSS的2倍),故而拥塞控制再次进入慢启动阶段。

何为TCP超时重传?
TCP服务必须能够重传超时时间内未收到确认TCP报文段。为此,TCP模块为每个TCP报文段都维护一个重传定时器,该定时器在TCP报文段第一次被发送时启动。如果超时时间内未收到对方的应答,TCP模块将重传TCP报文段并重置定时器。

所谓超时,是指定时器 > 最大往返时间RTT。
RTT是指一个数据报发送到目的地,然后到发送方收到确认所需的时间,这是测量RTT。发送报文和确认报文并非数量上的一一对应,可能发送多次,确认一次,也可能是一一对应。


快速重传和快速恢复

如何通过接收到重复的确认报文段,判断网络是否真的发生拥塞?
发送端接收到重复的确认报文段可能情形:TCP报文段丢失,接收端收到乱序TCP报文段并重排等。

拥塞控制算法需要判断当收到重复的确认报文段时,网络是否真的发生了拥塞,或者说TCP报文段是否真的丢失了。具体做法:
发送端如果连续收到3个重复的确认报文段,就认为拥塞发生了。然后它启用快速重传和快速恢复算法来处理拥塞,过程如下:

1)当收到第3个重复的确认报文段时,按(3)式计算ssthresh,然后立即重传丢失的报文,而不是等到重传计时器超时,这称为快速重传。并按式(4)设置CWND

CWND = ssthresh + 3 * SMSS                             (4)

2)每次收到1个重复的确认时,设置CWND = CWND + SMSS,而非从慢开始算法的cwnd=1开始。此时,发送端可以发生新的TCP报文段(如果新的CWND允许的话)

3)当收到新数据的确认时,设置CWND = ssthresh(ssthresh是新的慢启动门限值,由第一步计算得到)

步骤1)称为快速重传,步骤2)3)称为快速恢复。快速重传和快速恢复完成之后,拥塞控制将恢复到拥塞避免阶段。这点由第3)步操作可得知。


总结

拥塞控制对象:发送窗口SWND. SWND <= min(RWND, CWND)
网络出现超时 => 采用慢开始算法 + 拥塞避免算法;
网络出现重传 => 快速恢复算法;


参考

[1]谢希仁. 计算机网络.第5版[M]. 电子工业出版社, 2008.
[2]游双. Linux高性能服务器编程[M]. 机械工业出版社, 2013.
[3]Postel J . Transmission control protocol; rfc793[J]. Rfc, 1981.(RFC793)
[4]Тезисы, Статусдокумента, Авторскиеправа, et al. RFC 5681 TCP Congestion Control. 1996.(RFC5681)

posted @ 2021-07-22 00:17  明明1109  阅读(1173)  评论(0编辑  收藏  举报