为什么TCP over TCP是个坏主意

一个经常出现的想法是:将IP tunnel应用程序运行在PPP等协议上,该协议通过基于TCP的连接以适合于流传输的格式封装IP数据包。

通过在SSH上运行PPP来加密隧道,这将是一个简单的解决方案,对此已经存在一些建议(如:Linux HOWTO base中)。这也是一种压缩任意IP流量的简便方法,而基于数据报的压缩则很难克服效率限制。

TCP’s retransmission algorithm – TCP的重传算法

TCP将数据流分为多个Segments,这些Segments将作为单独的IP数据报发送。这些段带有一个 对流中的字节进行编号的Sequence Number,以及一个告知对方最后接收到的序列号的 Acknowledge 。[RFC793]

由于IP数据报可能会丢失、重复或重新排序,因此使用Sequence Number来重组流。Acknowledge间接地告诉发送方某个Segment是否丢失:当最近发送的SegmentsAcknowledge在一定时间内未到达时,发送方将假定此数据包丢失并重新发送该segments

使用类似方法的许多其他协议(主要设计用于带宽相对固定的线路)具有固定或可配置的“一定时间”。

但是,在Internet中,带宽,延迟和丢包率之类的参数在一个连接与另一个连接之间差异很大,甚至在单个连接上会随着时间而变化。在千兆链路上以秒为单位的固定超时将是不合适的,而在拥挤的国际链路上同样将是不合适的。实际上,这会增加拥塞并导致一种称为“meltdown”的效应。

因此,TCP将自适应超时用于所有与时序相关的参数。它们从保守的估计开始,并随每个接收到的段动态变化。在[RFC2001]中描述了实际使用的算法。此处的细节并不重要,而是一个关键属性:当segments超时时,从此之后的超时会逐渐增长(实际上,它们是以指数方式增长,因为这表明可以避免 meltdown 的影响)。

Stacking TCPs – 堆叠TCP

TCP超时策略可以在Internet上通过各种不同的连接特性正常运行。因为TCP尽最大努力不断开连接,所以超时可能会增加到几分钟的范围。这正是无人值守的批量数据传输的明智之举。(对于交互式应用程序,这种缓慢的连接当然是不可取的,并且用户很可能会终止它们。)

当将一个TCP连接堆叠在另一个TCP连接之上时,这种对可靠性的优化会被打破,这是在设计TCP的时候预料不到的。当在SSH或其他基于tcp的协议上运行PPP时,就会发生这种情况,因为PPP封装的IP数据报可能携带基于tcp的负载,就像这样:

tcp-tcp

要注意的是,上层和下层TCP具有不同的超时计时器。当上层连接十分快速时,其计时器也很快。

现在可能发生的情况是,低层的TCP具有较慢的计时器,这可能是因为低层连接较慢或不可靠。

想象一下,在这种情况下,低层连接开始丢失数据包时会发生什么。较低层的TCP将开始重传,并增加其超时时间。由于在这段时间内连接被阻塞,因此上层(即有效负载)TCP将无法及时获得ACK,并且还会继续重传。因为上层的超时时间仍然小于下层超时,所以上层将比下层发送更多的快速重传包。这使得上层连接非常快速地停顿,并且每次重新传输都加剧了这种问题 —— 内部崩溃效应。

TCP的可靠性规定在这里适得其反。上层重传是完全没有必要的,因为其载体可以保证可靠性传输,但是上层TCP无法知道这一点,因为TCP始终假设不可靠的载体。

参考文献

http://sites.inka.de/bigred/devel/tcp-tcp.html


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!