我的理解是它涉及网络中存在的同一数据包的多个副本。但这种情况最终是如何发生的呢?为什么它如此有害?
什么是拥塞崩溃?
首先,我将首先要求您忽略排队。假设以下文本中的路由器根本没有队列。在不考虑队列的情况下理解拥塞是可能的。所以在下面的文本中,一个数据包进入路由器,要么立即传输,要么被丢弃。(我会在这个答案的最后写几行关于排队的内容。)
关于拥塞,首先要了解的是:接口只能以有限的速度运行。一个 10Gbps 以太网接口可以以 10Gbps 的最大速率传输数据包,仅此而已(如果数据包的长度约为 1000 字节,则相当于每秒大约一百万个数据包)。
好的,现在考虑这样的路由器:
+----------------------+
--------------o a |
| |
--------------o b |
| x o----------------
--------------o c |
| |
--------------o d |
+----------------------+
假设数据包从接口 (a, b, c, d) 进入并离开 x(即从左到右)
假设 x 是一个 100Mbps 的接口。
假设开始时 (a + b + c + d) 的流量速率正好是 100Mbps。所有这些数据包都在 x 上发出。到现在为止还挺好。
现在让我们说其中一个接口,比如说 d 开始获得更多流量。现在 (a + b + c + d) > 100Mbps
此时,必须丢弃一些数据包。哪个,不好说。丢弃的数据包可能来自 a、b、c 或 d,或来自某些或所有这些接口。据说此时发生了拥塞。
好的,现在假设发送流量的主机(即位于图表左侧的主机)实现了一个简单的 TCP 版本。天真的实现说:“让我们发送 15 个数据包(一个“窗口”),然后等待 50 毫秒的确认。如果没有,让我们再次发送这 15 个数据包。在我们放弃并声明之前,让我们这样做 100 次连接已死”。
好的,回到我们的场景。假设当由于 d 上的流量增加而开始拥塞时,受害者是在接口 a 上碰巧收到的单个数据包。
由于天真的实现,原始不幸的数据包的发送者现在意识到:“嘿,我发送的窗口的ack发生了什么?看起来我的同伴没有收到,让我重新发送”并继续做所以。所以现在 'a' 最终收到了 15 个数据包的新副本。
同时,x仍然拥塞。'a' 上的新一批 15 个数据包只会使情况变得更糟,并导致在 'b'、'c' 和 'd' 上接收到的数据包也被丢弃。
只要天真的实现在行动,随着时间的推移,这种情况只会越来越糟。
解决方案:用更智能的东西替换幼稚的实现。例如,在接收 ack 失败时,不要发送整个 15 个数据包窗口;而是发送逐渐变小的窗口。没有固定的超时,在重新传输之前等待逐渐更长的时间。和其他类似的巧妙技巧。
我希望上面的解释足以提供一个直观的画面。其他地方有关于确切避免机制的文档。
[队列:路由器队列的存在不会改变上述总体情况。唯一的区别是数据包不会立即被丢弃,而是会排队一段时间。队列深度不是无限的;在上面描述的拥塞场景中,队列最终也会被填满,并保持这种状态(它们被填满的速度比排空的速度要快),导致后续的数据包被“拖尾”。换句话说,面对终端主机的朴素 TCP 实现,路由器上队列的存在并没有改善这种情况。路由器有完全不相关的队列:(1)暂时吸收小 突发流量,(2) 作为实施优先级的机制,以及 (3) 作为实施 RED 的机会,RED 是一种避免机制]
“同一个数据包的多个副本” 这句话让我很困惑,直到我意识到你的意思是“重传同一个数据包”。就网络而言,重传是新的数据包。从主机的角度来看,它们可能与先前传输的数据包具有相同的内容,但就网络而言,它们仍被视为新数据包。特别是,IPv4“标识符”字段在重传时会有所不同。
无论如何,您可以看到,在我上面描述的场景中,最终情况会变得如此糟糕,以至于在 a、b、c 和 d 上收到的所有(或大部分)流量将只是重新传输较早的数据包,即网络并不是真正的做任何有用的事情。
当传入流量超过节点转发容量时,多余的部分将存储在队列缓冲区中。如果这种情况持续超过(非常)短的时间,则缓冲区溢出并丢弃接收到的数据包。网络拥塞。
丢弃的数据包需要由源重新传输。这些重传代表之前在瓶颈前面的链路上浪费的带宽。
当拥塞发生时,源节点需要检测到这一点并减少其传输带宽以停止或至少减少丢包。如果这不能正常工作,重传会继续将入口流量添加到瓶颈节点并使问题恶化。由于入口与出口容量比非常大,拥塞状况会导致有用与无用流量的比率极低。