Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TCP 协议(2) - 拥塞控制 #41

Open
bigwolftime opened this issue Sep 11, 2021 · 0 comments
Open

TCP 协议(2) - 拥塞控制 #41

bigwolftime opened this issue Sep 11, 2021 · 0 comments

Comments

@bigwolftime
Copy link
Owner

https://bigwolftime.github.io/TCP-ctrl/

一. 拥塞控制原理

当网络中对某资源的需求量超过了该资源力不能及的部分, 网络的性能就会变坏, 即发生了拥塞.

引用«计算机网络»:

有人可能会说:“只要任意增加一些资源,例如,把结点缓存的存储空间扩大,或把链路更换为更高速率的链路,或把结点处理机的运算速度提高,
就可以解决网络拥塞的问题。”其实不然。这是因为网络拥塞是一个非常复杂的问题。简单地采用上述做法,在许多情况下,不但不能解决拥塞问题,
而且还可能使网络的性能更坏。

网络拥塞往往是由许多因素引起的。例如,当某个结点缓存的容量太小时,到达该结点的分组因无存储空间暂存而不得不被丢弃。现在设想将该结点缓存
的容量扩展到非常大。于是凡到达该结点的分组均可在结点的缓存队列中排队,不受任何限制。由于输出链路的容量和处理机的速度并未提高,
因此在这队列中的绝大多数分组的排队等待时间将会大大增加,结果上层软件只好把它们进行重传(因为早就超时了)。由此可见,简单地扩大缓存的
存储空间同样会造成网络资源的严重浪费,因而解决不了网络拥塞的问题。

又如,处理机处理的速率太慢可能引起网络的拥塞。简单地将处理机的速率提高,可能会使上述情况缓解一些,但往往又会将瓶颈转移到其他地方。
问题的实质往往是整个系统的各个部分不匹配。只有所有的部分都平衡了,问题才会得到解决。

拥塞控制与流量控制的关系密切,它们之间也存在着一些差别。所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过
载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与
降低网络传输性能有关的所有因素. 但TCP连接的端点只要迟迟不能收到对方的确认信息,就猜想在当前网络中的某处很可能发生了拥塞,但这时却无法
知道拥塞到底发生在网络的何处,也无法知道发生拥塞的具体原因(是访问某个服务器的通信量过大?还是在某个地区出现了自然灾害)。

流量控制往往指点对点通信量的控制,是个端到端的问题(接收端控制发送端)。流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。

从大的方面看,夜色控制可以分为开环控制和闭环控制两种方法。

开环控制方法就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。但一旦整个系统运行起来,就不再中途进行改正了;
闭环控制是基于反馈环路的概念(获取全局的网络状况, 根据情况动态调整)

二. 拥塞控制方法

RFC 2581定义了进行拥塞控制的四种算法: 慢开始、拥塞避免、快重传和快恢复。

  1. 慢开始和拥塞避免

发送方维持一个叫做拥塞窗口 cwnd 的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口。
以后我们就知道,如果再考虑到接收方的接收能力,那么发送窗口还可能小于拥塞窗口。

发送方控制拥塞窗口的原则是:只要网络没有出现拥塞, 拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小
一些,以减少注入到网络中的分组数。

发送方又是如何知道网络发生了拥塞呢?当网络发生拥塞时,路由器就要丢弃分组。因此只要发送方没有按时收到应当到达的确认报文,就可以猜想网络
可能出现了拥塞。

慢开始算法: 当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。经验证明,
较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。通常在刚刚开始发送报文段时,先把拥塞窗口
cwnd设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS(最大报文长度)的数值。用这样的方法
逐步增大发送方的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。

举例:

在一开始发送方先设置 cwnd = 1,发送第一个报文段M1,接收方收到后确认M1。

发送方收到对M1的确认后,把cwnd从1增大到2,于是发送方接着发送M2和M3两个报文段。

接收方收到后发回对M2和M3的确认。发送方每收到一个对新报文段的确认(重传的不算在内)就使发送方的拥塞窗口加1,因此发送方在收到两个确认后,
cwnd就从2增大到4,并可发送M4~M7共4个报文段因此使用慢开始算法后,每经过一个传输轮次,拥塞窗口cwnd就加倍。

一个传输轮次所经历的时间其实就是往返时间RTT。不过使用“传输轮次”更加强调:把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已
发送的最后一个字节的确认。例如,拥塞窗口cwnd的大小是4个报文段,那么这时的往返时间RTT就是发送方连续发送4个报文段,并收到这4个报文段的
确认,总共经历的时间。

为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量(如何设置ssthresh,后面还要讲)。
慢开始门限ssthresh的用法如下:

当cwnd < ssthresh时,使用上述的慢开始算法。

当cwnd > ssthresh时,停止使用慢开始算法而改用拥塞避免算法。

当cwnd = ssthresh时,既可使用慢开始算法,也可使用拥塞避免算法。

无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有按时收到确认),就要把慢开始门限ssthresh设置为出现拥塞时
的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,
使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。如下图:

(1)当TCP连接进行初始化时,把拥塞窗口cwnd置为1。慢开始门限的初始值设置为16个报文段,即ssthresh = 16。

(2) 在执行慢开始算法时,拥塞窗口cwnd的初始值为1。以后发送方每收到一个对新报文段的确认ACK,就把拥塞窗口值加1,然后开始下一轮的传输
(请注意,横坐标是传输轮次)。因此拥塞窗口cwnd随着传输轮次按指数规律增长。当拥塞窗口cwnd增长到慢开始门限值ssthresh时(即当cwnd = 16时)
,就改为执行拥塞避免算法,拥塞窗口按线性规律增长。

(3) 假定拥塞窗口的数值增长到24时,网络出现超时(这很可能就是网络发生拥塞了)。更新后的ssthresh值变为12(即变为出现超时时的拥塞窗口数值
24的一半),拥塞窗口再重新设置为1,并执行慢开始算法。当cwnd = ssthresh = 12时改为执行拥塞避免算法,拥塞窗口按线性规律增长,每经过一个
往返时间增加一个MSS的大小。

其中 乘法减小 和 加法增大 的概念:

乘法减小是指不论在慢开始阶段还是拥塞避免阶段,只要出现超时(即很可能出现了网络拥塞),就把慢开始门限值ssthresh减半,即设置为当前的拥塞
窗口的一半(与此同时,执行慢开始算法)。当网络频繁出现拥塞时,ssthresh值就下降得很快,以大大减少注入到网络中的分组数。

加法增大是指执行拥塞避免算法后,使拥塞窗口缓慢增大,以防止网络过早出现拥塞。上面两种算法合起来常称为AIMD算法(加法增大乘法减小)。

  1. 快重传和快恢复

如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。在这种情况下,TCP马上
把拥塞窗口cwnd减小到1,并执行慢开始算法,同时把慢开始门限值ssthresh减半.

再看使用快重传的情况。快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)
而不要等待自己发送数据时才进行捎带确认。

如下图: 接收方收到了M1和M2后都分别发出了确认。现假定接收方没有收到M3但接着收到了M4。显然,接收方不能确认M4,因为M4是收到的失序报文段
(按照顺序的M3还没有收到)。根据可靠传输原理,接收方可以什么都不做,也可以在适当时机发送一次对M2的确认。但按照快重传算法的规定,
接收方应及时发送对 M2的重复确认,这样做可以让发送方及早知道报文段M3没有到达接收方。

发送方接着发送M5和M6。接收方收到后,也还要再次发出对M2的重复确认。这样,发送方共收到了接收方的四个对M2的确认,其中后三个都是重复确认。

快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必继续等待为M3设置的重传计时器到期。由于发送方
能尽早重传未被确认的报文段,因此采用快重传后可以使整个网络的吞吐量提高约20%。

与快重传配合使用的还有快恢复算法,其过程有以下两个要点:

(1) 当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把慢开始门限ssthresh减半。这是为了预防网络发生拥塞。请注意,接下去不执行
慢开始算法。

(2) 由于发送方现在认为网络很可能没有发生拥塞(如果网络发生了严重的拥塞,就不会一连有好几个报文段连续到达接收方,也就不会导致接收方连续
发送重复确认),因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为慢开始门限ssthresh减半
后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。

如下图, 其中标注了“TCP Reno版本”,这是目前使用得很广泛的版本。图中还画出了已经废弃不用的虚线部分(TCP Tahoe版本)。它们的区别就是:
新的TCP Reno版本在快重传之后采用快恢复算法而不是采用慢开始算法。

在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant