知乎上的一个问题,TCP in TCP隧道为什么不好

版权声明:本文为博主原创,无版权,未经博主允许可以随意转载,无需注明出处,随意修改或保持可作为原创! https://blog.csdn.net/dog250/article/details/81257271

周六晚上本来是想把遗留的BBC六集纪录片《古罗马-一个帝国的盛衰》最后一集看完的,可是想起一件事还没有总结,就先搁置一下,待我先说事。


我一般不刷知乎的,上周有一天下班的路上,坐在公交车的最后一排实在没有什么好玩的了,刷了一会儿知乎,发现了一个问题:
为什么p2p模式的tunnel底层通常用udp而不是tcp?https://www.zhihu.com/question/39382183/answer/404245930

显然,这种专业性问题少不了知乎上领域大牛们的关注,一般而言,知乎上领域专家的套路是,关注所有的相关问题,不管能不能回答先关注,然后一段时间后筛选出比较火爆的问题,撸一遍已经有的回答,最后强答,这无疑是一种攒粉的绝佳方式,不过对于读者,弊端就是,很多千赞的回答往往不是最佳的回答,只是答者的粉丝多而已,这就是我一般不怎么相信知乎的原因之一。

我宁可针对问题的回答写成一篇文章,然后发布在固定的地方,不求点赞,只是备忘,非常客观。


回到知乎上的那个TCP in TCP的问题。

老掉牙的问题了。这个问题我很早的时候就分析过,来自OpenVPN的manual上的一个链接:
Why TCP Over TCP Is A Bad Ideahttp://sites.inka.de/bigred/devel/tcp-tcp.html

这篇文章说的非常清楚不过了。它定性地分析了原因和结果,文章篇幅不长,大概屙一个大号不到的时间就能读完,建议阅读我下面的文字之前先读一下这篇文章,毕竟我写的东西也是针对这篇文章的读后感


TCP in TCP不是不好,而是根本就不可用,为什么呢?原因源自于TCP协议本身的设计。

TCP的可靠性保证是基于丢包检测和重传的,它依赖于下面的事实:TCP的下层链路是不可靠的!

请注意,是依赖于下层链路不可靠”这个事实的。也就是说,如果说下层链路是可靠的,那么TCP的这种重传机制就是不必要的。很显然,TCP in TCP则是违反了上述的事实,即TCP构建在一条可靠的链路上:
这里写图片描述

我们来看看横向的图示,来分步解析一下:
这里写图片描述

问题就出在,TCP的可靠性是靠超时重传来保证的(当然,还有快速重传,但根本还是超时重传)!!而超时时间,即RTO是一个基于RTT动态计算的值,我们知道,TCP的RTT本质上是测不准的(为什么测不准,这里不谈,总之,TCP无法保证RTT测量值的准确性,但QUIC可以!),这会导致TCP1和TCP2的超时timer到期时间的关系是任意关系,只要TCP2的丢包重传造成了TCP1的超时,就会发生令人遗憾的重传叠加。

扫描二维码关注公众号,回复: 3303918 查看本文章

什么是重传叠加?重传叠加就是两层TCP均发生了针对同一个数据包的重传,而我们知道这是冗余的,不必要的。一旦内层TCP1的重传速度稍微大于外层TCP2的重传速度,数据包就会在R1处堆积。根据排队论我们可以得知,此时的服务率是0,而到达率非0,队列会指数级增长,后者触发TCP1更加激烈的丢包超时重传,最终连接崩溃,速率断崖跌落到0点,万劫不复!!

你以为上面的这些都是理论上的分析吗?非也!我在2010年年底的时候亲自排查过一个关于TCP模式的OpenVPN的此类问题,最终的结果就是重传叠加,事实上,上面的分析不是理论分析,而可以看作是我对当时情况的排查报告分析。


也许针对知乎上那个问题的回答到这里就要结束了,但是这看起来并不过瘾,这里给出一个论文,好好的过把瘾:
Understanding TCP over TCP: Effects of TCP Tunneling on End-to-End Throughput and Latencyhttp://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.78.5815&rep=rep1&type=pdf

这篇论文总结了TCP in TCP这种模式对数据传输特征的影响,而不是在说某种结论性的东西。论文在进行模拟仿真实验时,基于下面的拓扑:

这里写图片描述

大体上,该论文阐述了TCP in TCP对端到端连接吞吐量,RTT的影响,我把它们总结对有效吞吐率和RTT的影响,如下图:
这里写图片描述

嗯,自认为很清晰的总结,很不错。

我来解释一下第二张图。为什么在传播延迟A比较大的情况下,TCP隧道会造成端到端的RTT增大。答案是数据包会在R1处排队。

为什么会排队?理论分析看来,TCP1和TCP2的拥塞控制窗口CWND是同步打开的啊,也就是说它们是一致的,hostA发送的数据包总是会被R1的TCP2精准消费掉,为什么还会排队?

答案是在TCP2的隧道pipe被填满之后呢?这里所谓的TCP2 pipe的理解,真的要去看看《TCP/IP详解(卷1)》,基本上就是下面的图:
这里写图片描述
对,它就是TCP雅各布森管道!我在下面的文章中详细谈了它被填满的过程以及TCP拥塞避免的本质:
TCP核心概念-慢启动,ssthresh,拥塞避免,公平性的真实含义https://blog.csdn.net/dog250/article/details/51439747
TCP自时钟/拥塞控制/带宽利用之脉络半景解析https://blog.csdn.net/dog250/article/details/51694591

我再来稍微解释一下。

如果没有R1,R2以及它们之间的隧道,那么在R1和R2这段路径上,这是一个“带有时间延展性的第一类缓存”,然而如果在R1和R2之间构建一条TCP隧道,当TCP2的pipe被拥塞避免机制填满之后,R1将作为“非时间延展的第二类缓存”起作用,HostA上的TCP发送端是意识不到R1的存在的,它只会在拥塞避免的机制下继续增加拥塞窗口的大小,只要不超时,它不care这些多出来的数据包早就在R1上排队了,换句话说,它会持续增大CWND,充分利用R1的缓存。我们知道,只要有排队,就会把排队时间平添到RTT上,这解释了为什么TCP in TCP隧道会增加端到端的RTT。

我觉得解释的已经够详细了吧…如果有不懂的,我想你一定在纠结BDP,带宽以及goodput,throughput之间的区别和联系,请仔细澄清即可。


在这篇论文中,还描述了SACK,socket buffer,R1 buffer对端到端特征的影响,请仔细阅读原文。

此外,值得注意的是,隧道TCP2的握手开销是不重要的,我们完全可以事先提前构建好隧道,而不是懒惰按需构建。回答握手开销的并没有抓住本质,回答NAT相关的更是扯淡,NAT本身就是trick,它更跑题,再者,说什么外层包装TCP2导致平添20字节以及外层IP的开销,载荷率变低,这个稍微沾边,但也无关紧要,虽然这可能导致IP分片,但我难道不能说隧道的MTU更大吗?

这个问题,提问者问这个问题,从描述上看,提问者并不是小白,相反可能是一位很有经验的人,不然他怎么会知道“p2p模式的tunnel”这个词,如果提问者是小白,他首先要问“什么是tunnel”才对,所以还是直接切入比较好,大量篇幅解释什么tunnel概念,然后不到两行很笼统地回答一些并非本质的字词句,这明显是为了攒粉或者自我包装后的自我推销,我是非常讨厌的。无理,无数据,怎么能给人以帮助?

这就是我不喜欢知乎的原因。

知乎和微博一样,是一个互动的平台,对于严肃的知识,并不需要互动,因为但凡有互动就会发生社交网络上固有的马太效应,即最终会产生大拿,大咖,这一切的背后并不是因为这个人多么多么牛,而是幂律!懂得推销自己,就能成功。总之,知乎慢慢变成了一个演员的名利场。像那些经常强答的所谓大牛,大咖,他们有很多的途径将这种互动连接在知乎上变现。呵呵,不多说。


最后,我就认真说一句,我为什么这么关注这个关于TCP in TCP的tunnel问题,因为:

  • 我曾经不止一次遇到过TCP in TCP导致的连接崩溃问题并且成功解决之(有事实);
  • 我真的是比较懂TCP的,不管是协议层面还是行为控制层面,比如拥塞控制(有理论);
  • 我真的是很讨厌TCP协议的,但我很喜欢隧道(有情感)。

如此这般,我反问我有资格回答这个问题吗?

哈哈,我只是把针对这个问题以及针对知乎的分析和情感,表达在了这里,而已。

不多说。


现在是晚上11点了,终于把这文章写完了,明天是周日,所以我决定把《古罗马-一个帝国的盛衰》最后一集看完,嗯,很不错的纪录片,BBC的片子好看没悬念:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/dog250/article/details/81257271