TCP 的拥塞控制

摘自:《深入理解计算机网络》 王达著 机械工业出版社
相关知识链接
1. IPV4数据报头部格式
2. IPv4数据报的封装与解封装
3. IPv4数据报的分段与重组
4. TCP的主要特性
5. TCP的套接字
6. TCP端口
7. TCP连接状态转移
8. TCP传输的建立
9. TCP 传输链接的释放
10. TCP 的可靠传输
11. TCP 的流量控制

TCP 的拥塞控制

TCP中最复杂的功能可能就是拥塞功能了,因为两端经过的网路数量、网络类型、网路性能非常不稳定,而这些因素又深深地影响着 TCP 连接拥塞控制的复杂性和难度。TCP 的拥塞控制主要是依靠 TCP 连接双方商定的协议来减少数据的发送而实现的。

TCP 拥塞控制简介

顾名思义,拥塞控制(congestion control)就是要控制“网络拥塞”的出现。什么情况下会出现网络拥塞呢?简单的说,网路中各个部分输入的流量大于输出的流量时就会出现拥塞。打一个比较类似的比喻(之所以说是“类似”,因为它更像“流量控制”类的比喻),就像公路上发生塞车的一个根本原因就是出口道路太窄,而入口道路又比较宽导致同一时间驶入的车辆数大于驶出的车辆数,最终使得这条路上排队并挤满了各种车辆,车辆的行驶速度自然会降下来。最坏的情况是什么,那就是完全“堵死”,车辆根本出不去,也进不来。这就类似网络中通常所说的“死锁”现象。

当然,道路上发生塞车的原因不仅只有上面所说的那一个,还有像上游驶入的车辆太多、中间或下游正在进行车辆安全检查、中间某些车辆行驶速度太慢,或者发生了交通事故而占用部分道路等。就像道路发生塞车的原因有多种一样,网络上发生拥塞的原因也可能是多方面的,而且网络结构越复杂,发生拥塞的原因也可能越复杂。如 TCP 连接的整个链路中有结点设备的缓存空间太小、数据转发能力太低、某段链路带宽太小、对端数据接收能力低等,都有可能引起网络拥塞。而且,往往是多个因素同时存在,因此,处理拥塞控制问题不能简单地针对某一方面来解决,必须从全局角度来寻找方案,否则不仅不能解决拥塞现象,反而会形成新的瓶颈,使网络更拥塞。

例如,用户想单方面地提高中间路由器结点的数据转发能力,而忽视了所经路径上各段链路的带宽,结果是虽然提高了路由器转发性能,也提高了数据转发速度,但也同时造成了在链路上排队前行的数据不断增多,这样不仅没有解决网络拥塞问题,反而使网络拥塞程度更严重。再如,用户想单方面地提高路由器的缓存能力,但没有同步考虑路由器的数据转发能力和链路带宽,结果是虽然可以使更多数据在路由器上暂时缓存,但是在缓存中排队的数据所需等待的时间会更长,因为队列比以前更长了,结果会因为超市重传这些数据。重传数据越多,网络负荷越重,最终导致拥塞更加严重。就像我们在车站买票,如果售票员的售票速度没有提高,仅仅增加用于排队的等候空间,就会让队列拍得更长,这样是不能解决长时间排队买票的难题的,反而使得后面的人买到票的时间更长,同时使得售票厅更加拥挤。

如果把整个网络有效处理负荷的能力成为“吞吐量(throughout)”,而把网络中发送端输入的负荷成为“输入负荷(input load)”,则理想的情况下他们之间有如图所示的线性关系(吞吐量是呈 45 度斜线上升的)。


理想情况下的吞吐量与输入如何之间的关系
理想情况下的吞吐量与输入如何之间的关系

如上图所示,在开始时网络系统的吞吐量随着输入负荷的增加呈同步提高态势(两者的提高量是一致的),但当到了一定时期(在输入负荷达到了网络的最大吞吐量时),输入负载再怎么增加,网络系统的吞吐量也不再提高了,而是保持在一个不变的水平。这时就出现了轻度拥塞现象。就像一条河流最初没有水的,当上游河流放水,它的水速会随着上流流入水的水速提高而提高,但当这个条河流满了之后,也就是到了它的最大负荷水平时,它的水速不会再有提高了,尽管上流流入的水速仍在提高。从上游新增的那部分水哪里去了呢?肯定是溢出了,就像网络达到最大吞吐量时,从发送端发来的超出吞吐量那部分的数据会被丢弃一样。

上图只是一种理想情况,实际上网络系统吞吐量与输入负荷之间的关系永远不会是线性关系。因为网络中不可能完全是理想状态,所以一开始“吞吐量”和“输入负荷”之间的关系就不是呈现线性关系了。当输入负荷到达或接近最大吞吐量时,如果继续提高输入负荷,此时网络系统的实际吞吐量是不会保持最大吞吐水平的,而是呈现下降趋势的;如果此时输入负荷继续增加,那么最终可能导致网络系统的吞吐量下降到 0,出现完全死锁状态,如下图所示。


实际情况下的吞吐量与输入负荷之间的关系
实际情况下的吞吐量与输入负荷之间的关系

TCP 拥塞控制方案

虽然已经了解了发生拥塞的原因,也知道了网络系统吞吐量与输入负荷之间的关系,但要真正设计一套有效的拥塞控制方案却不是一件容易的事情,因为拥塞的出现和所引起的因素都是动态的,是在不断变化的。发生网络拥塞的一个最明显额征兆就是出现了数据丢失。于是,为了防止网络出现拥塞现象,出现了一系列的 TCP 拥塞控制机制。最初是由 Jacobson 在1988年的论文中提出的 TCP 拥塞控制机制,由“慢启动(slow start)”和“拥塞避免(congestion avoidance)”组成,后来在 TCP Reno 版本中又针对性加入“快速重传(fast retransmit)”、“快速恢复(fast recovery)”算法。为了方便介绍,先假设数据是单方面发送的,另一个方向只传送确认数据段,而且假设接收端的窗口足够大,发送端的窗口大小由网络拥塞程度决定。

慢启动

慢启动是指为了避免出现网络拥塞而采取的一种 TCP 拥塞初期预防方案。其基本思想就是在 TCP 连接正式传输数据时,每次可发送的数据大小(这就是“拥塞窗口”的定义)是逐渐增大的,也就是先发送一些小字节的试探性数据,在收到这些数据段的确认后,再慢慢增加发送的数据量,知道达到了某个原先设定的极限值。(也就是下面将要提到的“慢启动阈值(SSTHRESH)”)为止。

在“慢启动”拥塞解决方案中,发送端除了要维护正常情况下根据接收端发来的“窗口大小”字段值而调整“发送窗口”外,还要维护一个“拥塞窗口(Congestion Window,CWND)”,它是为了避免发生拥塞而设置的窗口,最终允许发送的字节数是这两个窗口中的最小值。如果从接收端返回的“窗口大小”字段值是 100,而当时设置的“拥塞窗口”大小为 50,此时只能发送 50 字节的数据。相反,如果从接收端返回的“窗口大小”字段值是 100,而当时设置的“拥塞窗口”大小为 200,则此时只能发送 100 字节的数据。下面仅假设“拥塞窗口”总是小于从接收端返回的“窗口大小”字段值(也就是“发送窗口”的大小)。具体步骤如下:

1) 在一个 TCP 传输连接建立时,发送端将“拥塞窗口”初始化为该连接上当前使用最大数据段大小(Maximum Segment Size,MSS),即 CSND = MSS,然后它发送一个大小为 MSS 的数据段。

2)如果在定时器过期前发送端收到了该数据段的确认,则发送端将“拥塞窗口”大小在增加一个 MSS,也就是此时的 CWND 大小为 2MSS。然后发送 2MSS 大小的数据。

3)如果这次发送的 2MSS 数据段也都被确认了,则“拥塞窗口”大小再增加两个 MSS(此时相当于达到了4个 MSS),以此类推。

下图是一个采用“慢启动”方案的示例,其中 M 代表 MSS,表示“最大数据段大小”。第一次发送一个 MSS(即M1),收到 M1 的确认后,再连续发送两个 MSS(即 M2 和 M3),当收到 M3 的确认(因为后面的已经确认的话,预示着前面的都已经正确接受,下同)后再发送4个 MSS (即 M4 ~ M7),当收到 M7 的确认时,后面将发送8个 MSS(即 M8 ~ M15)


“慢启动”解决方案TCP数据发送示例
“慢启动”解决方案TCP数据发送示例

“慢启动”方案的基本规律:当“拥塞窗口”大小达到了 n 个 MSS 时,如果所有 n 个数据段都被及时确认,则新的“拥塞窗口”大小再增加 n 个 MSS,也就是说新的“拥塞窗口”大小是旧的“拥塞窗口”大小的2倍关系,即“拥塞窗口”大小与最大数据段大小(MSS)的关系是2的指数关系,即 1MSS、2MSS、4MSS、8MSS、16MSS、32MSS

但是“拥塞窗口”不可能无限制地继续增大,即使 CWND 值仍小于从接收端返回的“窗口大小”字段值,都有可能在某个时刻出现数据丢失的现象。这个“拥塞窗口”大小是一个临界点,于是引入了“慢启动”方案的另一个重要参数——“慢启动阈值(Slow Start Threshold,SSTHRESH)”,其初始值为 64KB,即65535字节。当发生一次数据丢失时,SSTHRESH 设为当前 CWND 的一半,而 CWND 再次增长到 SSTHRESH (此时仅为原来 CWND 的一半)时便停止使用“慢启动“方案,需采用下面将要介绍的”拥塞避免“解决方案。

拥塞避免

当 CWND 再次大于或者等于 SSTHRESH 时,启动“拥塞避免”解决方案。它的基本思路是在 CWND 值第二次达到 SSTHRESH 时,让“拥塞窗口”大小每经过一个 RTT (一个数据段往返接收端和发送端所需要的时间)时间仅值加1(即新的 CWND 只增加一个 MSS 大小,而不是原来的 CWND 的几倍),使其以线性的方式慢慢地增大,而不是继续像“慢启动”方案那样以指数方式快速增大。显然,这种 CWND 增长速度明显要慢于“慢启动”方案中的 CWND 增长速度。当再次发生数据丢失时,又会把 SSTHRESH 减为当前 CWND 的一半,同时把 CWND 置1,重新进入慢启动数据发送过程,依次类推。

下图是一个“慢启动”和“拥塞避免”两种拥塞控制方案的控制示例。假设最初在某个时间的“拥塞窗口”大小(CWND)为 64KB,而就在此后发生了数据丢失,没有收到后面发送的数据的确认,于是 SSTHRESH 减为 CWND 的一半,即 32KB(即下图中的“第一次调整的阈值”),同时把新的 CWND 设为 1MSS,从坐标原点开始重新采用“慢启动”方案进行数据发送,当达到了 SSTHRESH 值(即 32KB)时,采用“拥塞避免”方案进行数据发送,每个 RTT 时间 CWND 只增加一个 MSS。但在第 11 次传输过程中(此时 CWND = 38KB)又发生了一次数据丢失,于是 SSTHRESH 再次降为当前 CWND (即 38KB)的一半(即 19KB),并且重新开始采用“慢启动”方案发送数据,直到达到新的 SSTHRESH 值(即 19KB),然后从这点开始又采用“拥塞避免”方案发送数据,以此类推。


“慢启动”和“拥塞避免”方案数据发送示例
“慢启动”和“拥塞避免”方案数据发送示例

快速重传/快速回复

上面介绍的“慢启动”和“拥塞避免”是1988年提出来的方案,而1990年又新增了两种拥塞控制方案,就是下面要介绍的“快速重传”和“快速回复”拥塞控制方案。

“快速重传”方案的基本思想:当接收端收到一个不是按序到达的数据段时,TCP 实体迅速发送一个重复 ACK 数据段,而不用等到有数据需要发送时顺带发出确认;在重复收到三个重复的 ACK 数据段后,即认为对应“确认号”字段的数据段已经丢失,TCP 不用等到重传定时器超时就重传看来已经丢失的数据段。

为了进一步了解“快速重传”原理,现在举一个例子,如下图所示。假设每次只发送一个大小等于 MSS 的数据段,并假设在第一次、第二次发送 M1、M2 后,发送端都从接收端收到了确认,但第三次发送的 M3 在途中丢失了,继续发送 M4,在接收端收到 M4 时,为了尽快通知发送端 M3 还没有收到,于是再次发送一个 M2 确认数据段(其中“确认号”字段值是 M3 的序号),相当于再次提醒发送端 M3 数据段还没有收到,希望再等等看,,仍然继续依次发送 M5、M6,在接收端没收到一个数据段后均会有一个重复的 M2 确认。在发送端收到四个针对 M2 数据段确认时(一个确认 M2,三个重复确认 M2)时,发送端就会立即发送 M3,尽管此时可能 M3 的重传定时器还没有过期。

在“快速重传”算法发送了看似已经丢失的数据段后,“快速恢复”算法同时开始发挥作用。“快速恢复”算法的思想是:在收到第三个重复 ACK 时,把当前的 CWND 值设为当前 SSTHRESH 值得一半,以减轻网络负荷,然后执行前面介绍的“拥塞避免”算法,使 CWND 值慢慢增大,以避免再次出现网络拥塞。


“快速重传”方案数据重传示例
“快速重传”方案数据重传示例

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值