网络拥塞(congestion)是指在分组交换网络中传送分组的数目太多时,由于存储转发节点的资源有限而造成网络传输性能下降的情况。当网络发生拥塞时,一般会出现数据丢失,时延增加,吞吐量下降,严重时甚至会导致“拥塞崩溃”(congestion collapse)。通常情况下,当网络中负载过度增加致使网络性能下降时,就会发生网络拥塞。
另外一种说法,在网络中,链路带宽、节点的缓存、处理设备都是资源,当对资源的需求大于提供,网络的性能就会下降,就会出现网络拥塞。网络拥塞是全局的一个状态,不能仅仅改变一个部分的性能来改善,比如拥有了一台无限缓存的路由器,当分组的输入大于处理设备的能力时候,分组就会逐步在缓存堆积,以至于当缓存中的分组还未发送时,发送端迟迟收到不到应答,超时后重发了分组,更加加剧网络的拥塞。或者提高处理设备的能力,但是这样就将瓶颈丢到了别的地方,只有当全局的设备趋于平衡的时候,整个网络才能才能够顺畅运行。
拥塞控制和流量控制也是有一定的差别的,拥塞控制就是防止过多的数据涌入网络,导致网络处理不过来,是全局的,涉及所有的主机路由器。当TCP连接迟迟收不到应答就可以认定为网络发生了拥塞。只是无法确定在何处发送。
而流量控制就是防止数据输出过快导致对方来不急处理,是端对端的控制,只要抑制发送端的发送速率即可。
拥塞控制和流量控制经常会被人们给混淆,主要是一些拥塞控制算法同样会将控制信息发送给发送端来,这点和流量控制一致。当然如果网络发生拥塞,拥塞控制算法还要发送控制信息,这些信息同样会加剧网络拥塞。
拥塞控制
TCP 拥塞控制常用的下列四种算法,慢开始
拥塞避免
快重传
快恢复
。为了介绍这几种算法,假设下列2情况。
1.接受方只是对数据报做出应答,不进行传输数据。
2.接受方的滑动窗口数无限大的。因为实际的窗口上限 = Min(接受方的滑动窗口数,发送方的拥塞窗口数),这样的发送窗口数就大小就有拥塞窗口数来决定。
接下来讨论是基于拥塞窗口数 cwnd(congestion windos),实际上拥塞窗口的单位是字节,在这里我们为了减少复杂度,理解算法的核心内容,讨论中的拥塞窗口数就用 SMSS(Sender Max) 作为单位
这个拥塞控制算法的核心思想就是:刚刚建立连接的时候,假设网络是拥塞的,先向网络传输一点数据。等到确认数据接收完毕后,就继续加大数据向网络里面塞。当窗口是超过阈值的时候,系统认为网络可能要发生拥塞,就减少了窗口数增大的速率。当系统通过某一种方式得知了网络发生了拥塞,就减少数据发送效率来缓解网络状况。
下面逐步讨论各个算法对 cwnd 值的影响。
慢开始
慢开始,顾名思义,就是开始的时候很慢。在网络连接刚刚建立的时候,连接双端并不知道网络的拥塞状态,如果立即将一堆的数据涌入网络,就可能导致网络拥塞,或者加剧网络拥塞。目前的探测方式是开始的时候发送一点数据,来逐步探测网络拥塞状态。
RFC 5861 规定初始的 cwnd 不能超过 2~4 个 SMSS 值。
SMSS > 2199 字节
cwnd = 2 * SMSS 字节;
1095 字节 < SMSS ≤ 2199 字节
cwnd = 3 * SMSS 字节;
SMSS ≤ 1095 字节
cwnd = 4 * SMSS 字节;
还进行了规定,每接受到一个新的确认报文后,就对 cwnd 进行更新。假设收到的确认报文,确认的字节数为 X。那么每次接受到报文后拥塞窗口增加的数量为 Min(X,SMSS)。
e.g. 这里可能会有人问了,每次发送的报文最大也就是 SMSS,那么怎么会出现比SMSS大的情况呢?
接下来的例子为了方便说明,这里将cwnd设置为整数。
在下图中,连接刚刚建立的时候,系统将 cwnd 设置为1,每次系统受到确认后,都会对 cwnd 经行增加。系统发送了 M1,之后受到了 M1 的确认后。将 cwnd 加一,并同时发送 M2M3。所以每经过一个传播轮次,cwnd 就会翻倍。
这里的慢不是指增长的慢(每次都翻倍,显然不会慢),而是开始设置的 cwnd 值很小。这个的确是个不错的方法来避免一下子向网络中发送很多的数据,导致网络拥塞。既然增加速度这么快,如果持续发送数据那么一段时间后,网络中必然发生拥塞。就需要用到拥塞避免算法。
拥塞避免
拥塞避免的意思就是避免网络拥塞,如果按照之前慢开始
算法中,cwnd的增长速率来看,势必没过一段时间就会发生一次拥塞,然后将 cwnd 设置为1,重新进行慢开始,对于你的网络来说,感知就忽快忽慢,网络很不稳定。这里就引入了拥塞避免
算法,与其共生的还有一个名词ssthresh
,全称 slow start threshold,也就是慢开始阈值。当 cwnd 大于等于这个值以后,就不再采用慢开始算法了。就采用了拥塞避免算法。
而拥塞避免算法,一般都是在 cwnd 比较大的时候才启动,用于避免网络拥塞。而拥塞避免不是在是对每个响应都会增加 cwnd ,只有经过了一个 RTT 才会加一,或者说是收到了 cwnd 个应答才进行加一。
在下图中,建立连接的时候,我们将 ssthresh 设置为16,cwnd设置为1。刚刚开始 cwnd 没超过阈值,增加的速度是很快的,每经过一个轮次就翻倍,当达到点1 的时候,就采用拥塞控制算法,每经过一个轮次就才加一,按照线性增长,这样网络不容易发生用拥塞。
到达点2的时候,网络发生拥塞了,网络出现了超时。就将 ssthresh 设置为 cwnd 的一半,并将 cwnd 重新设置为1 ,重新开始慢开始算法。到点3 时,达到了阈值,继续采用了拥塞避免算法。
快重传、快恢复
在上图中,点4出现了一个新的情况,发送方连续3次收到了同样一个 ack 分组。这种情况说明,这个分组之后的临近的那个分组在网络中出现错误,导致接受方未收到,这情况下网络不一定发生了拥塞,如果接受方不进行通知的话,发送方就会采取超时策略,将 cwnd 降低到 1,这样会很大程度降低了网络传输效率。采用快速重传就可以让发送方早知道,个别报文在网络传输中丢失了。只需要将丢失的报文重传即可,而不需要将之后的所有报文都进行重传,这里就需要接受方对收到的乱序分组都及时做出应答。
只要发送方一连收到3个重复的ack分组后,就可以认为该分组在网络传输中出现了差错,立即重新传输该分组,可以有效的减少了超时情况,整体网络吞吐量上升了20%。
同时发送方知道只是丢失个别保存,ssthresh 同样也会设置成 cwnd 的一半,但是cwnd并不会设置为1,而是现在的一半,并且开始采用拥塞避免算法。也会有别的快恢复实现会将 cwnd = cwnd/2 + 3 * MSS。应该之前的重复确认报文有3次,说明至少有3个分组离开了网络。因此将 cwnd 设置成更大。
网络层拥塞管理
之前讨论的都是传输层协议的。这里我们要对网络层协议进行深入的讨论,毕竟两者是息息相关的。最主要的就是路由器对分组的处理策略,会对整体网络的影响,在路由器的缓存中,通常都是采取 FIFO 先进先出策略。这里就引入了,常见的两种策略,尾部丢弃策略、随机早期检测。
尾部丢弃策略
尾部丢弃策略,就是当路由器的缓存满时,会直接丢弃新进来的分组,通常会丢弃一连串的分组,发送方就会出现超时,导致 TCP 连接进去慢开始状态。由于是尾部丢弃,就会丢弃掉所有的 TCP 连接的分组数据。就会导致全部 TCP 同一时间全部进入慢开始,这个称为全局同步,网络流量一下子骤然减小,随着网络的恢复,流量又骤然增大,导致网络再次发生拥塞。
随机早期检测 RED
显然上面的策略不合理,避免全局同步,在1998年就提出了主动队列管理 AQM,而随机早期检测 RED 就是其实现之一。主动队列管理就是在路由器端自行维护一个队列,这个队列拥有2个阈值,最小门限,最大门限。当一个分组进入到路由器的时候。
1.当队列中的数据数量小于最小门限,直接放入队列中。
2.当队列中数量大于最大门限,直接丢弃该分组。
3.当队列中数量数量大于最小门限,但是小于最大门限,该按照一定概率p被丢弃,将该分组进行丢弃。
由此可见,当队列中的值大于最小门限的时候,网络已经开始了拥塞控制。只是不像之前那样进行全局同步,这样可以在可能要发生网络拥塞的早期就进行管理,将拥塞控制在个别tcp连接上。但是在这里最难处理的就是概率p,需要按照网络进行动态调整,这里就不进行将讲解了,这个策略在2015年就被标记过时的。
显式拥塞控制 ECN
ECN:explicit congestion notification,显示拥塞控制。是运行在IP协议和TCP协议中的一种可选拥塞控制策略,运行通过数据标识来代替丢包的方式来告知网络拥塞状态。ECN的实现需要在建立连接的时候通讯双方进行协商,协商成功,相应的路由器可以通过设定 IP 数据包的标志位来通知拥塞,而连接的双方也可以通过 TCP 数据报 | IP 数据报 中的相应标识来来进行拥塞窗口控制。
网络层
在图中 IP 首部格式中,14位和15位就是通过这两位来进行标记。其中第14位为 ECT
第15位为 EC
。这两个参数会出现以下 4 种情况。其中01
和10
可以认为都代表支持网络拥塞控制,并无明显区别。
-
00
不支持显示拥塞控制 -
01
支持显示拥塞控制,ECT(0) -
10
支持显示拥塞控制,ECT(1) -
11
网络发生了拥塞
当通讯双方协商好采用 ECN 后,通讯双方发送出来的 IP 数据报就被标记为 ECT(0) 或者 ECT(1) ,然后当该数据报经过支持 ECN 的路由器时候就会对数据进行控制,当网络达到可能要发生拥塞的时候就会采取对数据包进行标记来取代丢包,当通讯一端接受到报文的时候,就可认为该网络发生了拥塞,并通过TCP报文将拥塞信息回显,通知发送端。
TCP层面
在 TCP 协议中则是采用了保留字段的低三位来进行拥塞标识。
NS
Nonce Sum,随机和,用于进行数据保护标识,防止意外或恶意隐藏来自TCP发送方的标记数据包 CWR
Congestion Window Reduced 减少拥堵窗口标识,由发送主机设置,表明收到了由拥塞控制机制设置 ECE 标识的分组, ECE
ECN Echo。当 SYN = 1 时,该值表明具有 ECN 能力,当 SYN = 0时,当收到了 ECN = 11 的数据报时候,设置该值,来回显网络拥堵,提示即将到来的拥堵。当一个端口收到了 ECE 标识的TCP分组,就会像丢包一样来减少拥塞窗口数,并发出 CWR 位的段来确认拥塞指示。
当两个支持ECN的TCP端进行TCP连接时,它们交换SYN,SYN-ACK和ACK包。对于支持ECN的TCP端来说,SYN包的ECE和CWR标志都被设置了。SYN-ACK只设置ECE标志。只要这样的协商后该链路就支持ECN控制,之后的每个携带数据的分组(不包括纯 ACK、FIN、SYN)都会将其 IP 头部 ECN 字段设置为 ECT(0)。
1.当这个分组经过了支持 ECN 又发生了拥塞的路由器时候,路由器就将 ECN 设置为 11。
2.当接受方收到了ECN 标志位 11 的分组后,就进行应答 ACK 并将 ECE 字段标志位1,并且之后的分组都会携带上这个标记。
3、发送端接收到了带有 ECE 标记的分组后,得知网络拥塞,对 cnwd 和 ssthresh 进行控制,并在下一个发送分组中携带 CWR 标志。
4.接受端收到了 CWR 标志的分组,就对之后发送的分组取消 ECE 标记。从而完成了一次显示拥塞控制。
性能影响
由于ECN仅在配合活动队列管理(AQM)策略时有效,因此ECN的益处依赖于所用的AQM的精确度。
如预期那样,ECN减少TCP连接中被丢弃的数据包数量,以避免重传、减少等待时间,尤其是网络抖动。当TCP连接有单个未完成段时,这种效果最为明显[9],它可以避免传输控制协议(RTO)超时;这通常发生在交互式连接时,例如远程登录,以及事务协议,例如HTTP请求、SMTP的会话阶段、SQL请求。
ECN对批量吞吐的效果不太明确,因为现代的TCP实现在发送方的窗口足够大时对于及时处理段丢失相当友好。
ECN的使用已被发现在高度拥塞的网络上是有害的,AQM算法使数据包不会被丢弃。现代的AQM实现在极高负载下会丢包而非标记包来避免这个陷阱。