计算机网络-5-9-TCP拥塞控制

TCP拥塞控制

拥塞控制的一般原理

在计算机网络中的链路容量(带宽),交换节点中的缓存和处理机等,都是网络的资源,在某段时间,若对网络中某一资源的需求超过该资源所能提供的可用部分,网络性能就会变坏,这种情况叫做拥塞(congestion)

计算机网络-5-9-TCP拥塞控制

若网络中有许多资源同时呈现供应不足,网络的性能就要明显的变坏,整个网络的吞吐量将随着输入的负荷增大而下降。

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

又如,处理机处理的速率太慢可能引起网络的拥塞。简单地将处理机的速率提高,可能会使上述情况缓解一些,但往往又会将瓶颈转移到其他地方。问题的实质往往是整个系统的各个部分不匹配。只有所有的部分都平衡了,问题才会得到解决。拥塞常常趋于恶化。如果一个路由器没有足够的缓存空间,它就会丢弃一些新到的分组。但当分组被丢弃时,发送这一分组的源点就会重传这一分组,甚至可能还要重传多次。这样会引起更多的分组流入网络和被网络中的路由器丢弃。可见拥塞引起的重传并不会缓解网络的拥塞,反而会加剧网络的拥塞。

拥塞控制与流量控制的关系密切,它们之间也存在这差别:

  • 拥塞控制就是防止过多的数据注入到网络中,这样可以使得网络中的路由器或者链路防止过载,拥塞控制所要做的都有一个前提,就是网络中能够承受现有的网络负载。拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能相关的所有因素。

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

在图 5-23 中的横坐标是提供的负载(offered load),代表单位时间内输入给网络的分组数
目。因此提供的负载也称为输入负载或网络负载。纵坐标是吞吐量(throughput),代表单位
时间内从网络输出的分组数目。具有理想拥塞控制的网络,在吞吐量饱和之前,网络吞吐量
应等于提供的负载,故吞吐量曲线是 45°的斜线。但当提供的负载超过某一限度时,由于网
络资源受限,吞吐量不再增长而保持为水平线,即吞吐量达到饱和。这就表明提供的负载中
有一部分损失掉了(例如,输入到网络的某些分组被某个结点丢弃了)。虽然如此,在这种理想的控制作用下,网络的吞吐量仍然维持在其所能到达的最大值。

计算机网络-5-9-TCP拥塞控制

但是,实际的网络情况就不相同了,从图5-23中可以看出,随着提供的负荷增大,网络吞吐量的增长速率逐渐减小。也就是说,在网络吞吐量还未到达饱和的时候,就已经有一部分的输入分组被丢弃了。当网络的吞吐量明显的小于理想的吞吐量时,网络就进入了轻度的轻度拥塞的状态。更值得注意的是。当提供的负载达到某一数值的时候,网络的吞吐量就下降为0,网络已无法工作,这就是所谓的死锁(deadlock)

拥塞控制是很难设计的,因为它是一个动态的(而不是静态的)问题。当前网络正朝着高速化的方向发展,这很容易出现缓存不够大而造成分组的丢失。但分组的丢失是网络发生拥塞的征兆而不是原因。在许多情况下,甚至正是拥塞控制机制本身成为引起网络性能恶化甚至发生死锁的原因。这点应特别引起重视。

由于计算机网络是一个很复杂的系统,因此可以从控制理论的角度来看拥塞控制这个问题。这样,从大的方面看,可以分为开环控制闭环控制两种方法。开环控制就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。但一旦整个系统运行起来,就不再中途进行改正了。

闭环控制是基于反馈环路的概念,主要有以下几种措施:

  • 监控网络系统一边检测到拥塞在何时、何处发生。

  • 把拥塞发生的信息传送到可采取行动的地方。

  • 调整网络系统的运行以解决出现的问题。

有很多的方法可用来检测网络的拥塞。主要的一些指标是:由于是缺少缓存空间而被丢弃的分组的百分数、平均队列长度、超时重传的分组数、平均分组时延的标准差,等等。上述这些指标的上升都标志着拥塞的增长。

一般在检测到拥塞发生变化的时候,要将拥塞发生的信息传送到产生分组的源站。当然,通知拥塞发生的分组同样会使网络更加拥塞。

另一种方法是在路由器转发的分组中保留一个比特或者字段,用该比特或字段的值表示网络没有拥塞或者产生了拥塞。也可以由一些主机或路由器周期性的发出探测报文,以询问拥塞是否发生。

此外,过于频繁地采取行动以缓和网络的拥塞,会使系统产生不稳定的振荡。但过于迟缓地采取行动又不具有任何实用价值。因此,要采用某种折中的方法。但选择正确的时间常数是相当困难的。下面就来介绍更加具体的防止网络拥塞的方法。

TCP拥塞控制方法

TCP 进行拥塞控制的算法有四种,即慢开始(slow-start)、拥塞避(congestionavoidance)、快重传(fast retransmit)和快恢复(fast recovery)(见 2009 年 9 月公布的草案标准RFC 5681)。下面就介绍这些算法的原理。为了集中精力讨论拥塞控制,我们假定:

  • 数据是单方向传送的,对方只传送确认报文。

  • 接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定。

慢开始和拥塞控制

下面讨论的拥塞控制也叫作基于窗口的拥塞控制。为此,发送方维持一个叫做拥塞窗口cwnd(congestion window) 的状态量。拥塞窗口的大小取决于网络的拥塞程度,并且动态的在变化,发送方让自己的发送窗口等于拥塞窗口

发送方控制拥塞窗口的原则是:只要网络上没有出现拥塞,拥塞窗口就可以再大一些,以便把更多的分组发送出去,这样就提高了网络的利用率。但只要出现网络拥塞,就必须减少拥塞窗口的值,以缓解网络出现的拥塞。

发送方又是如何知道网络出现拥塞了?我们知道:当网络发生拥塞的时候,路由器就会丢弃分组。因此只要发送方没有按时接收到应当到达的确认报文(超时),就可以猜测网络中出现了拥塞。现在通信线路的传输质量都比较好,一般出现丢弃分组的概率是很小的(一般远小于1%)。因此,判断网络拥塞的依据就是出现了超时。

下面将讨论拥塞窗口cwnd的大小是如何变化的。我们从“慢开始算法”讲起。

慢开始算法思路:当主机开始发送数据时,由于并不清楚当时网络的负载情况,所以如果立即发送大量数据,就有可能导致网络出现拥塞甚至瘫痪。需要先验证一下比较好,最好的办法就是先探测一下,即由小到大逐大逐渐增大发送窗口。也就是说,由小到大逐渐增大拥塞窗口数值

旧的规定是这样的:在刚刚开始发送报文段时,先把初始拥塞窗口cwnd设置为1至2个发送方的最大报文段SMSS(Sender Maximum Segment Size)的数值,但新的RFC5681把初始拥塞窗口cwnd设置为不超过2至4个SMSS的数值。具体的规定如下:

  • 若SMSS>2019字节:则设置初始拥塞窗口cwnd=2xSMSS字节,且不得超过2个报文段。

  • 若SMSS>1095字节并且SMSS<=2190字节:设置初始拥塞窗口cwnd=3xSMSS字节,且不得超过3个报文段。

  • 若SMSS<=1095字节:则设置初始拥塞窗口cwnd=4xSMSS字节,且不得超过4个报文段。

可见这个规定就是限制初始拥塞窗口的字节数。

慢开始规定,在每收到一个对新的报文段的确认后,可以把拥塞窗口增加最多一个SMSS的数值,更具体些,就是

\(拥塞窗口cwnd每次的增加量=min(N,SMSSs)\)

这里N为原先未被确认的、但现在被刚收到的确认报文段所确认的字节数。不难看出,当N<SMSS时,拥塞窗口每次增加量要小于SMSS。

用这样的方法逐步增大发送方的拥塞窗口cwnd,可以使分组注入到网络的速率更加合理。下面用例子说明慢开始算法的原理。请注意,虽然实际上 TCP 是用字节数作为窗口大小的单位。但为叙述方便起见,我们用报文段的个数作为窗口大小的单位,这样可以使用较小的数字来阐明拥塞控制的原理(如图5-24)。

计算机网络-5-9-TCP拥塞控制

在一开始发送方先将cwnd=1,发送第一个报文M1,接收方收到后确认M1。发送方收到对M1的确认后,把cwnd从1增加到2,于是发送方接着发送M2和M3两个报文段,接收方收到发回对M2和M3的确认。发送方每收到一个对新报文段的确认(重传的不算在内) 就使发送方的拥塞窗口+1,因此发送反在接收到两个确认后,cwnd就从2增加到4,并可以发送M4~M7共4个报文段(如图5-24)。因此在使用慢开始算法后,每经过一个传输轮次(transmission round),拥塞窗口cwnd就加倍

这里我们使用了一个名词:传输轮次。从图 5-24 可以看出,一个传输轮次所经历的时间其实就是往返时间 RTT(请注意,RTT 并非是恒定的数值)。使用“传输轮次”是更加强调:把拥塞窗口 cwnd 所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。例如,拥塞窗口cwnd的大小是4个报文段,那么这时的往返时间RTT就是发送方连续发送4个报文段,并收到这4个报文段的确认,总共经历的时间。

我们还要指出,慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置 cwnd = 1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大 cwnd。这当然比设置大的 cwnd 值一下子把许多报文段注入到网络中要“慢得多”。这对防止网络出现拥塞是一个非常好的方法。

顺便指出,图 5-24 只是为了说明慢开始的原理。在 TCP 的实际运行中,发送方只要收到一个对新报文段的确认,其拥塞窗口 cwnd 就立即加 1,并可以立即发送新的报文段,而不需要等这个轮次中所有的确认都收到后(如图 5-24 所示的那样)再发送新的报文段。

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

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

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

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

拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口cwnd加1®,而不是像慢开始阶段那样加倍增长。因此在拥塞避免阶段就有“加法增大”AI(Additive Increase)的特点。这表明在拥塞避免阶段,拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

图 5-25 用具体例子说明了在拥塞控制的过程中,TCP 的拥塞窗口 cwnd 是怎样变化的。图中的的数字1至5是特别要注意的几个点。现假定TCP的发送窗口等于拥塞窗口。当 TCP 连接进行初始化时,把拥塞窗口 cwnd 置为 1。为了便于理解,图中的窗口单位不使用字节而使用报文段的个数。在本例中,慢开始门限的初始值设置为 16 个报文段,即ssthresh = 16。在执行慢开始算法时,发送方每收到一个对新报文段的确认ACK,就把拥塞窗口值加 1,然后开始下一轮的传输(请注意,图 5-25 的横坐标是传输轮次,不是时间)。因此拥塞窗口 cwnd 随着传输轮次按指数规律增长。当拥塞窗口 cwnd 增长到慢开始门限值ssthresh 时(图中的点1,此时拥塞窗口 cwnd = 16),就改为执行拥塞避免算法,拥塞窗口按线性规律增长。但请注意,“拥塞避免”并非完全能够避免了拥塞。“拥塞避免”是说把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。

计算机网络-5-9-TCP拥塞控制

当拥塞窗口 cwnd = 24 时,网络出现了超时(图中的点2),发送方判断为网络拥塞。于是调整门限值 ssthresh = cwnd / 2 = 12,同时设置拥塞窗口 cwnd = 1,进入慢开始阶段。按照慢开始算法,发送方每收到一个对新报文段的确认 ACK,就把拥塞窗口值加 1。当拥塞窗口cwnd = ssthresh = 12 时(图中的点1,这是新的ssthresh值),改为执行拥塞避免算法,拥塞窗口按照线性规律增大。

当拥塞窗口 cwnd = 16 时(图中的点 O),出现了一个新的情况,就是发送方一连收到 3
个对同一个报文段的重复确认(图中记为3-ACK)。关于这个问题要解释如下。

有时,个别报文段会在网络中丢失,但实际上网络并未发生拥塞。如果发送方迟迟收不到确认,就会产生超时,就会误认为网络发生了拥塞。这就导致发送方错误地启动慢开始,把拥塞窗口 cwnd 又设置为 1,因而降低了传输效率。

采用快重传算法可以让发送方尽早知道发生了个别报文段的丢失。快重传算法首先要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。如图 5-26 所示,接收方收到了 M 和M2后都分别及时发出了确认。现假定接收方没有收到 M3 但却收到了 M4。本来接收方可以什么都不做。但按照快重传算法,接收方必须立即发送对 M2 的重复确认,以便让发送方及早知道接收方没有收到报文段 M3。发送方接着发送 M5 和 M6。接收方收到后也仍要再次分别发出对 M2 的重复确认。这样,发送方共收到了接收方的 4 个对 M2 的确认,其中后 3 个都是重复确认。快重传算法规定,发送方只要一连收到3个重复确认,就知道接收方确实没有收到报文段 M3,因而应当立即进行重传(即“快重传”),这样就不会出现超时,发送方也不就会误认为出现了网络拥塞。使用快重传可以使整个网络的吞吐量提高约20%。

计算机网络-5-9-TCP拥塞控制

因此,在图 5-25 中的点4,发送方知道现在只是丢失了个别的报文段。于是不启动慢开始,而是执行快恢复算法。这时,发送方调整门限值 ssthresh = cwnd / 2 = 8,同时设置拥塞窗口cwnd = ssthresh = 8(见图5-25 中的点≤),并开始执行拥塞避免算法(\(ssthresh=max(FlightSize/2,2xSMSS)\))。

从图 5-25 可以看出,在拥塞避免阶段,拥塞窗口是按照线性规律增大的,这常称为加法增大 AI (Additive Increase)。而一旦出现超时或 3 个重复的确认,就要把门限值设置为当前 拥 塞 窗口值的一半,并大大减小拥塞窗口的数值。这常称为“乘法减小”MD(Multiplicative Decrease)。二者合在一起就是所谓的AIMD算法。

采用这样的拥塞控制方法使得TCP的性能有明显的改进。

根据以上所述,TCP 的拥塞控制可以归纳为图 5-27 的流程图。这个流程图就比图 5-25所示的特例要更加全面些。例如,图 5-25 没有说明在慢开始阶段如果出现了超时(即出现了网络拥塞)或出现 3-ACK,发送方应采取什么措施。但从图 5-27 的流程图就可以很明确地知道发送方应采取的措施。

计算机网络-5-9-TCP拥塞控制

在这一节的开始我们就假定了接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定。但实际上接收方的缓存空间总是有限的。接收方根据自己的接收能力设定了接收方窗口 rwnd,并把这个窗口值写入 TCP 首部中的窗口字段,传送给发送方。因此,接收方窗口又称为通知窗口(advertised window)。因此,从接收方对发送方的流量控制的角度考虑,发送方的发送窗口一定不能超过对方给出的接收方窗口值 rwnd。

如果把本节所讨论的拥塞控制和接收方对发送方的流量控制一起考虑,那么很显然,发送方的窗口的上限值应当取为接收方窗口 rwnd 和拥塞窗口 cwnd 这两个变量中较小的个,也就是说:

\(发送窗口的上限值=min[rwnd,cwnd]\)

当 rwnd < cwnd 时,是接收方的接收能力限制发送方窗口的最大值。
反之,当 cwnd < rwnd 时,则是网络的拥塞程度限制发送方窗口的最大值。
也就是说,rwnd 和 cwnd 中数值较小的一个,控制了发送方发送数据的速率。

主动队列管理AQM

上面讨论的TCP拥塞控制并没有和网络层采取的策略联系起来。其实,它们之间有着密切的关系。

例如,假如一个路由器对某些分组的处理时间特别的长,那么就可能导致这些分组中的数据部分(TCP报文段)经过很长的时间段才能到达终点,结果就有可能引起发送方对这些报文段的重传,由于重传会使得发送端认为网络中出现了拥堵,于是在TCP的发送端就采取了拥塞控制措施,但实际上网络上没有发生拥塞。

网络层的决策对TCP拥塞控制影响最大的就是路由器的分组丢弃策略,在最简单的情况下,路由器的队列通常是按照先进先出FIFO的规则来处理到来分组,但是队列长度是有限的,当队列满的时候,以后再到达队列的分组就会被丢弃掉,这也叫尾部丢弃策略(tail-drop policy)。

路由器的尾部丢失往往会导致一连串的分组丢失,这会使得发送方出现超时重传,使得TCP进入拥塞控制的慢开始阶段,结果使得TCP连接的发送方突然把数据的发送速率降低到很低,更严重的是,在网络中通常有很多TCP连接(它们有着很多不同的源点和终点),这些连接中的报文段通常是复用网络中的IP数据报传送。在这种情况下,若发生了路由器尾部丢弃,则可能会同时影响到很多条TCP连接,结果使得许多TCP连接在同一时间突然进入到慢状态。这在TCP的术语中叫做全局同步(global synchronization),全局同步使得全网的通信量突然下降了很多,而在网络恢复正常后,其通信量又突然增大了很多。

为了避免网络中的全局同步现象,在1998年提出了主动队列管理AQM(Active Queue Management),所谓主动,就是不要等到路由器里的队列长度满了才丢弃后面的分组,这样太被动了,应当在队列中队列的长度到达某一个长度(警惕值)的时候(当网络拥塞出现了某些拥塞的征兆),就应该主动丢弃到达的分组。这样就提醒了发送方应该放慢数据的发送速率,就可能使得网络中的拥塞情况相应的减少,避免出现网络拥堵情况。AQM有着不同的实现方法,例如:

随机早期检测RED(Random early detection),实现RED就需要使路由器维持两个参数:队列长度最小门限,最大门限,每当一个分组到达时,RED就按照规定的算法先计算当前的平均队列长度:

  1. 若平均队列长度小于最小门限,则把先到达的分组放入到队列中进行排队。

  2. 若平均队列的长度超过最大门限,则把新到达的分组丢弃。

  3. 若平均队列长度在最小门限和最大门限中间则按照一定的概率p,把新到达的分组丢弃掉(体现了丢弃分组的随机性)。

由此可见,RED不是等到已经发生拥塞后才把所有再队列尾部的分组全部丢弃掉,而是检测到网络拥塞的早期征兆(即路由器的平均队列长度到达一定数值的时),以概率p丢弃个别分组,让拥塞控制只在个别的TCP连接上进行,因而避免了全局性的拥塞控制。

在RED中,最难处理的就是丢弃概率p的选择,p并不是一个常数,对于每一个到达的分组,都必须重新计算丢弃概率p的值,这就比较难确定。因此2015年后标准不再推荐使用RED算法。但是对路由器进行主动路由管理AQM仍然是有必要的,AQM实际上是对路由器中的分组排队进行智能管理,而并不是简单的把队列的尾部丢弃掉,现在已经有不同的算法可以代替RED,但是都还在实验阶段,还没有成为IETF标准。

上一篇:HTTP请求原理


下一篇:《网络编程一》