TCP系列38—拥塞控制—1、概述

一、拥塞控制(Congestion Control)背景

        TCP协议一开始是没有拥塞控制的,但是在1986年10月,美国的NSFnet骨干网的速率由于负载过重(拥塞)导致实际速率下降为预期速率的千分之一,严重降低了网络性能。NSFnet是当时Internet的重要组成部分,为了避免拥塞或者有效的减轻拥塞状况改善Internet的性能,各路网络专家进行了TCP拥塞控制的一系列研究,时至今日仍然是一个热点研究领域。TCP的拥塞控制就是由相关算法控制的一系列TCP报文发送行为,主要目的是防止网络因为负载过重产生拥塞而影响网络性能。

        当TCP数据包经由网络中的路由器传输的时候,如果路由器的收包速度大于处理速度,路由器一般会先把收到的数据包缓存起来等待后续处理。但是当网络传输速度过大时,则会导致路由器的缓存空间全部被占用从而只能丢弃一部分数据包,如果一个路由器或者交换机等网络节点由于性能或者带宽等因素的限制而不能及时处理这些业务数据的时候,就会强制丢包,这种场景就叫做拥塞(congestion),这个节点叫做被拥塞(congested)

        那么网络的负载状况与网络的性能有什么关系呢?下图是网络负载与吞吐量和响应时间的关系,从图中可以看到在Knee点之前,随着网络负载的增加,网络吞吐量显著的线性增加,响应时间相对比较平稳,在Knee和Cliff之间,随着负载增加,网络吞吐量增速降低,吞吐量比较平稳,此时响应时间增长比较明显,在Cilff点之后,负载增加时,吞吐量显著下降,响应时间极速抬升,网络性能恶化,在严重的情况下就叫做拥塞崩溃(congestion collapse)为了避免或者改善这种情况,每个TCP都要实现拥塞控制过程(congestion control procedures)。TCP的拥塞控制目标就是让网络负载处于cliff点之前。

二、拥塞控制与流量控制

流量控制:指点对点通信量的控制,是端到端的问题。流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。流量控制是以显式(explicit)的方式在TCP头中通过Window size字段通告发送方。流量控制关注的是接收端和发送端。

拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制是一个全局性的过程,关注到传输链路上所有的主机、路由器,以及与降低网络传输性能有关的所有因素。拥塞控制大多是通过隐式(implicit)的方式控制发送端速率,接收端依据特定的收发包情况来推测网络拥塞状况。

三、拥塞检测(detection of congestion)

        为了处理拥塞,我们需要在拥塞发生的时候,降低TCP的速率,在拥塞解除后合理的抬升TCP的速率,这就要求我们具有检测何时发生拥塞何时拥塞解除的能力。但是实际上在Internet上面进行拥塞检测是很困难的,因为一般没有显式信号(explicit signaling)指示发送端网络拥塞状况。目前TCP拥塞检测主要有三种方式

1、利用丢包状况检测拥塞状况。当发送端检测到丢包的时候(有时候发送端检测到丢包并不一定是发生了拥塞,比如无线通信空口丢包等场景虽然发送端检测到了丢包但是并不是网络发生拥塞,但是在多数情况下丢包能在一定程度上面反应网络的拥塞情况),则认为网络发生了拥塞,TCP需要降低发送速率。这种方法是假设当数据包从发送端成功传到接收端的时候,接收端进行比特校验失败的概率很小(1%)。这样丢包才能有效指示网络发生拥塞。

2、利用时延检测拥塞。从上面介绍的网络传输响应时间可以看到在网络发生拥塞的时候,网络传输时延会显著增大。因此可以依据RTT的变化情况来推测网络的拥塞情况。

3、使用显式拥塞通告(ECN,explicit congestion notification)指示拥塞情况。ECN方式需要网络支持,这种拥塞检测方式允许TCP在发生丢包前检测到拥塞情况

在TCP早期一般是使用第1种方式利用丢包检测拥塞,后两种拥塞检测方式是后期发展出来的。

四、降低TCP发送端速率

        发生拥塞时需要降低TCP的发送速率,为此我们需要知道在拥塞控制中如何控制TCP的发送速率,在TCP流量控制部分我们通过接收端通告的窗口大小(awnd,即TCP头中的window size字段,RFC5681中也称呼为rwnd)来指示发送端根据接收端的剩余缓存空间来调整发送端速率。类似的我们可以在拥塞控制中设置一个拥塞窗口cwnd(congestion window)来调整发送端的速率,则发送端实际可用的发送窗口W为

W=min(cwnd,awnd)

通常W的单位是byte,但是文档描述中为了方便W经常表示大小为SMSS的packet的个数。已经发送但还没有被ACK确认的数据量叫做flight size,拥塞控制限制发送速率的方式就是让flight size<=W,另外有两点需要注意

1)在没有使用SACK时,flight size就是当前已经发送数据包的最大seq减去当前接收到的最大ACK Number。

2)在使用SACK时,flight size还需要扣除被SACK反馈的数据包。但是此时即使满足flight size<W,但是可能会由于流量控制的原因发送端仍然不能发送新数据。

        一般来说,W的合理值应该接近网络的带宽延迟积(BDP,Bandwidth-delay product),BDP是网络往返时间(Round Trip Time,RTT)和网络中所有节点的最低速率的的乘积,它反映了这个TCP连接在这个链路上最合适的flight size。但是由于路由、时延、网络的业务情况(比如多个TCP连接共同使用同一个网络节点而相互竞争资源)等因素随时会变化,因此准确的估计网络的BDP是很困难的。

       注意这里对于拥塞控制限制速率的描述是一种基于byte限制的描述,也就是说拥塞控制限制了发送的最大的byte数量。而在linux实现上是基于包的拥塞控制,也就是说限制了发送TCP数据包的最大个数。在发送新的TCP报文的时候Linux会先判断当前发送的这个TCP报文和已经发送的TCP报文的总个数是否超过了拥塞控制,然后在判断当前报文的最后一个byte对应的系列号是否超过了对端的awnd限制。只有两个判断都允许发送这个数据包的时候才会继续剩下的发送流程。

        基于byte的拥塞控制和基于包的拥塞控制基本思路是类似的,当把报文大小假设为SMSS的时候,基于byte的拥塞控制就可以转换为基于包的拥塞控制。之前我们在介绍TLP的时候也是类似的有这样两种TLP,linux采用的同样是基于包的TLP。

       本系列对于拥塞控制的讲解主要集中在发送端的拥塞控制,而实际上接收端反馈ACK的网络链路也可能会发生拥塞,RFC5690针对接收端的ACK拥塞提出了一种拥塞控制方法,感兴趣的可以自行参考。

补充说明:

1、http://www.cs.virginia.edu/~cs757/slidespdf/757-13-congestion.pdf

原文地址:https://www.cnblogs.com/lshs/p/00b5e5eeb4b165950e77f310069cc00c.html