TCP封装的隧道对于拥塞控制的意义

引:

工作上,平时上网,都用到了OpenVPN,事实上我比较喜欢用TCP模式而不用UDP(直到发现了重传叠加),因为自从上学时代,我就会UDP不感冒,它除了多路复用,分解的作用外,和IP几乎一样,而且根据我们的习惯,越复杂的东西越好,UDP简单,所以它不好!我不知道我们为何会有这样的想法,如果德国人和英国人也这样想,那很多好东西就都不会出现了,甚至都不会发生工业革命...后来,我发现,事情慢慢起了变化,不是想的那么简单,确实是这样,TCP有好处,也会带来问题,UDP是不好,同样也会带来问题,也会有一些优势,本文就针对我挖掘出的一些问题进行总结,不很全面,仅仅作为一个小结

1.一些词汇和短语的解释

正常传输队列:从应用层来一个数据,该数据就会被TCP封装,然后加入正常传输队列末尾。
重传队列:在正常传输队列中每发送一个TCP分段,该分段就会加入重传队列末尾。
正常传输:TCP会视发送窗口的大小以及窗口的可用性从正常传输队列头取出一个TCP分段,然后传输。
重传:
超时重传:从重传队列头取出一个TCP分段,重传之;
快速重传:从重传队列头依次取出一个个可能丢失的TCP分段,重传之;
避免不必要重传:在快速重传中,如果已经重传了可能丢失的TCP分段,理论上讲,按照标准,接下来会依次重传重传队列后面的所有TCP分段,然而如果是由于ACK丢失,或者接收端已经缓存了乱序的分段,这样的重传就是冗余的,由于正常传输队列和重传队列是分开的(重传队列和发送队列分离设计),此时发送正常传输队列中的当前可以发送(没有窗口限制和Nagel限制)的TCP分段可以有效地“带回一些ACK”这些ACK会清除重传队列里的TCP分段。因此根据这个策略,不必要的重传实际上是很少的。
背景流量:如果一条IP层链路上封装了一个隧道,所有非隧道的流量都是背景流量。

2.TCP隧道的问题

2.1.TCP拥塞控制的意义

注意,TCP本来是不包含拥塞控制的,但是因为它是端到端的协议,并没有运行于任何网络节点,因此裸TCP对于带宽是极其贪婪的,和UDP一样,当网络拥堵以后,TCP就加入了拥塞控制。然而端到端的协议并不仅仅就是TCP,虽然TCP加入了拥塞控制,可是UDP并没有,UDP本来就不关心丢包,网络拥塞了,丢包就是了。然而,UDP是情愿丢包也不进行拥塞控制,这确实是连累了TCP,结果就是TCP频繁的进入拥塞状态,不断的慢启动或者快速重传,导致TCP流量的颠簸,虽然诸多TCP流量都不断的徘徊在锯齿的峰谷之间,显得很公平,然而对于总体的带宽,在存在没有拥塞控制机制比如UDP流量的情况下,TCP的性能将急剧下降。
因此整个带宽对各个端到端协议流量的分配是不公平的。

2.2.TCP公平性

TCP的拥塞控制内在的实现了公平性,大家都会对拥塞快速反应。如果所有流量都是TCP,那再好不过了,带宽可以得到完全公平分配。

2.3.并不是所有的流量承载于TCP

然而,还有很多协议是没有拥塞控制的,比如UDP,大量贪婪的流量瞬间挤满整个通路,虽然大多数贪婪流量被丢弃了,然而发送端并不在乎,仍然继续快速大量发送,结果导致对丢包很在乎的TCP进入拥塞状态,TCP的退出,导致UDP流量不再被丢弃,结果,整个通路长期保持拥堵状态,TCP流量很难有机会再获得公平带宽,直到UDP流量的退出。

2.4.需要做的工作

现在怎么办?难道为UDP加入拥塞控制吗?这样不妥,那样对实时要求很高的UDP应用影响太大,因此需要一种更为温和的方式解决这个带宽在不同类型端到端协议之间的不公平分配问题。
这种温和的解决方式就是TCP隧道,简而言之,就是在核心网络的容易拥堵的三层链路的两个路由器之间部署一条TCP隧道,封装所有的流量,包括UDP的流量,这样,起码在该段通路上,带宽分配公平了,特别是,如果仅仅部署一条TCP隧道(所有流量通过该隧道)的话,排除中间路由器排队/路由处理的影响,拥堵是不会发生的。

2.5.TCP隧道导致的重传叠加

现在考虑一个问题,那就是TCP隧道之上的载荷也是TCP流量,这样的话,恰好TCP隧道上发生拥堵而丢包,这种情况下,载荷TCP超时也在预料之中,因此会发生重传叠加,事实上,我们知道,载荷的重传是不必要的,因为隧道是TCP的,所有的丢包都会得到重传。
我们可以把TCP隧道封装的一条网络通路想象成一个路由器,在该路由器中,只要得到排队的数据包都会安全可靠到达输出端口,在路由处理过程中不会丢包。这也许不太符合真实的路由器,因为真实的路由器中在路由处理的过程中很有可能发生错误的。既然是这样的话,我们就知道,一旦在这个虚拟的路由器中发生丢包,端TCP系统是不需要重传的,然而事实是,端到端的TCP协议永远都不知道是什么原因导致了丢包,并且更不知道丢包发生在哪里。
部署TCP隧道的时候需要做什么?很简单,就是尽量避免隧道的丢包,可以理解为不要让隧道和其它流量竞争带宽,那么可选的方案只有一个,就是部署TCP隧道的通路最好不要再有其它的流量,也就是不要拥有背景流量!

2.5.1.设计的意义:分层模型的层间功能不能重合

TCP是一个端到端的有连接的可靠传输的协议,它作为尽力而为的IP协议的载荷而存在,如果它跑在TCP之上的话,就会造成重传叠加,这样的话很多重传将是不必要的,因此从设计的角度看来,分层模型之间的功能最好不要重合。

2.6.TCP隧道导致的延迟增加

部署良好的TCP隧道虽然对于带宽的公平性有很好的促进作用,然而却会导致单个数据包延迟的增加,这个延迟的增加具体是什么原因导致的呢?其实很简单,那就是在TCP隧道的入口处,TCP分段要作为TCP载荷被封装,这个时间实际上完全是CPU完成的,这是延迟增加的原因。当然延迟虽然增加了,也不完全是坏事,后面我们会看到,通过TCP隧道的速率匹配,可能做到最大化吞吐量,毕竟,吞吐量和延迟总是满足反比律的。

3.有效利用TCP隧道

事情并不是想象的那么坏到了极点。这是因为还有比TCP更坏的,几乎所有的端到端协议都比TCP更可恶,因为它们都比TCP更贪心,所有的端到端协议都以为整个带宽都是自己的,而TCP起码还做了拥塞控制使得整个网络用户更加公平。既然如此,我们需要有效的利用TCP的这点优点。

3.1.有效利用公平性

载入拥塞控制机制的TCP的优点就是公平性,然而UDP和TCP们共享统一网络通路,却没有对拥塞进行反应,这样导致了网络带宽分配的严重不公,大量UDP流量会瞬间吃掉所有带宽。因此一个好的解决方案就是将UDP(以及其它所有的没有拥塞控制的端到端协议数据)封装在TCP隧道中。

3.2.TCP隧道在中间路由器上增加了容量适配功能

我们知道,在单一连接的链路上,延迟和带宽的乘积表示了该链路的容量,如果能始终保持链路的满载,那无疑是对网络带宽的最有效的利用,可惜的是,端到端的TCP并不能做到这一点,因为端到端之间要经过无数的二层链路,经过无数的路由器,往往中间的核心网络带宽是很大的,然而端系统的TCP却不可能认识到这一点,最有效的措施是在核心网最容易拥堵的链路上部署一个TCP隧道,以及在核心网容量差别最大的两条相邻链路之中的大容量链路上部署一条TCP隧道,这样该TCP隧道就会起到容量匹配的作用。
然而事情并不是这么简单,这个TCP隧道的构建是有要求的,事实证明,它的出入口缓存的容量达到该链路的延迟和带宽乘积,那将是最高效的。

3.3.TCP隧道减少了拥塞控制起作用的频率

TCP隧道显式的减少了流的数量,在构建了两条TCP隧道且没有背景流量的情况下,原来N个流量的带宽竞争现在成了两个TCP的竞争。更可贵的是,原来的N个流量中可能还有UDP流量,它会吃掉几乎整个带宽的哦!现在公平了,只有两个TCP,完全履行拥塞公平的原则。可见TCP隧道缩小了竞争者的数量,并且消除了贪婪者,是一个化干戈为玉帛的利器。
我们知道,TCP隧道本身封装了N个流量,它们之间的带宽分配是不加权的,要想实现N个被封装流量带宽的加权分配,最好的办法是按照协议类型对TCP隧道进行一些配置,比如UDP流量封装在一个TCP隧道中,TCP流量封装在另一个TCP隧道中,然后对排队规则进行配置,比如实时优先级高的UDP优先排队,或者同一TCP隧道中的统一端到端协议的不同流量按照路由器的配置进行加权排队...

3.4.强制措施

虽然TCP隧道可以解决网络带宽分配不公的问题,然而并不是所有人都能部署TCP隧道的,作为一种实验,在实验室可以随意配置,然而作为一种实施,你就必须依赖政府和运营商。ISP或者政府需要对整个核心网络规划十分了解,这样它们便知道在哪里部署TCP隧道了,更为重要的是,只有它们可以触动核心网络的配置,只有它们有权力这么做。

3.5.部署TCP隧道

我们知道,只有一个TCP连接的链路(也没有中间路由器)是没有拥塞的,因此总是能期望其数据传输最终使网络满载。
因此需要在流量很杂,UDP特别多的拥堵链路上部署TCP隧道,这样所有的流量就进入了一个隧道,为了避免UDP撑满整个隧道,有时需要部署两条TCP隧道,一条专门用于UDP,另一条用于别的,这样,UDP流量也要接受拥塞控制了。如果实现了解不用很惯着UDP,那么就可以只部署一条TCP隧道,这样的话,可以消除大部分的堵塞事件。

4.性能

4.1.Selected ACK的意义

选择重传实现了一种机制,可以只重传丢失的TCP分段,并且只要不是连续丢包就不用等待超时,只要接收端都到乱序分段就会在ack中附带sack信息,这样即使TCP隧道的丢包也会得到快速的选择重传,这种重传仅仅是TCP隧道两端的,远远比端到端的链路距离要短很多,这样端系统感知到的拥塞将会大大减小,减少了端系统TCP重传的次数,同时也提升了发送速率,因为进入慢启动的机会少了。

4.2.TCP隧道的缓冲区大小的意义

带宽,延迟的乘积表示了一个网络链路的容量,如果希望能获得很大的吞吐量和较小的延迟,保持整个链路容量满载是最有效的,然而要想避免拥塞,使TCP的拥塞控制不起作用,那么只能保持仅有一个TCP连接的状态,这样TCP的端到端的流控机制最终会使链路满载的。虽然由于可恶UDP流量的存在,不可能只部署一个TCP隧道,也就是说,最终TCP的拥塞控制还是会起作用,其时间-窗口图可能还是会出现经典的锯齿状,然而实验表明,保持TCP隧道入口缓冲区大小等于带宽,延迟的乘积的话,还是会得到最大的吞吐量。
可以想象,在这个场景下,TCP隧道起到了容量适配的作用。否则,仅凭各个TCP端用户疯狂在网络上争抢带宽,大量带宽将浪费在大量TCP用户拥塞控制导致的锯齿下尖角的位置。

4.3.TCP隧道对IP分片的影响

一旦由于MTU的影响,IP数据报分了片,一旦分片丢失,如果其上的载荷是TCP,那么将会导致端系统的TCP重传,在一条长长的且MTU变化很大并且还有点拥堵的三层链路上,IP分片很容易丢失,只要丢失一个分片,IP将不能重组,TCP分段也会玩完,在这种链路上,这很可能发生,如果只有1个数据报那么其丢失造成TCP分段不能接收的可能为10%,如果该IP数据报分了10个片,那么只要有一个分片丢失,那将造成同样的结局,毕竟IP是尽力而为的,这个信息最终会反馈到端TCP系统,如果在这种链路上的MTU突变造成分片的链路上部署一条TCP隧道,那么将把到达稳定链路的跳数减少为1跳,有效屏蔽了MTU突变造成的IP分片且丢失的影响。
记住,TCP隧道两端的路由器和中间的链路组成了一个虚拟路由器,该路由器只要数据排队就不会丢包,是一种名副其实的工业级路由器!TCP隧道的存在使N跳变成了1跳,好事!

5.影响TCP隧道性能因素

开门见山指出,就三点

5.1.TCP隧道的实现

这是一个很重要的因素,因为TCP隧道的实现有很多的方案,诸如OpenVPN的方式是一种很低效的实现,因为它是基于socket的,而socket是一个用户接口,它作用于端到端的系统,对于核心网行为的理解是很片面的,因此OpenVPN只能面对TCP隧道的问题而抛弃它(但是在udp被封堵的时候仍然支持它),OpenVPN始终没有认识到TCP隧道的优势,根据设计需求,它没有必要认识到...
更高效的实现方式是在内核协议栈中直接实现,像IPsec一样,对于Linux而言,这是很高效的,因为可在软中断中完成一切TCP隧道载荷的封装和解封装,避免了端系统进程调度系统带来的悲哀。

5.2.有没有背景流量

存在背景流量将是可悲的,如果背景流量是UDP的话,那将是致命的,本来N个TCP流量和UDP是并列的,然而N个TCP流量被封装了,即使这样,单独的UDP流量也可能吃掉带宽,因此部署TCP隧道的时候,一定不要UDP背景流量的存在,将它们封装在一个单独的加权值比较低的TCP隧道中是一个好方法。只要没有背景流量,tunnel是可靠的,一旦有背景流量,在TCP隧道中丢包,就会出现重复的重传叠加

5.3.原始链路的性质

如果原始链路本来就不拥堵,那么TCP隧道是没有意义的,只有在原始链路很拥堵或者背景流量很大的情况下,才要部署TCP隧道。

5.4.OpenVPN的问题

故事:
首先列出一个网址:http://sites.inka.de/bigred/index.html
它是一个开源VPN实现CIPE的作者的网站,其中有一篇文章《Why TCP Over TCP Is A Bad Idea》,从其名字可以看出,在实现隧道的时候,用TCP封装TCP并不是一个好主意。如今,虽然CIPE已经风光不再(它实际上从来都没有风光过,从未流行过),然而它的思想被最大限度的扩展了,其中之一就是“尽量不用TCP来封装IP隧道”。如今是OpenVPN的时代,在其man手册里,其proto字段的解释中,明确指出了一篇文章,旨在说明最好不用TCP作为封装协议,除非UDP不可用时才使用TCP,该文章就是《Why TCP Over TCP Is A Bad Idea》,这篇文章很简洁,没有专业术语,写得也很通俗易懂,不妨看一下
故事的一点解释:

TCP隧道用于OpenVPN等用户态的VPN实现时,加之部署这些VPN的组织并没有强制措施,因此其性能严重依赖于RTT的测量算法,,依赖于当前网络的状态,否则网络传输可能将不可用。OpenVPN的使用者不会部署整个核心网络的,因此他们不可能期望TCP隧道带来良好的收益,相反的,如果失去了强制措施,TCP隧道是弊大于利。

通过“TCP隧道对IP分片的影响”一节可以明白,在TCP隧道中传输大数据块(OpenVPN下超过100字节就算大了,因为虚拟网卡的动态mtu在某时就是100)的时候,最容易使得IP分片,一旦一个分片丢失就会导致重传叠加,就会引起问题,而对于交互式的TCP应用,重传叠加发生的几率很小,因此就会出现在拥有背景流量的TCP隧道上访问http会很慢,而登录SSH却没有问题。

记住,TCP隧道部署的意义:1.UDP和TCP全部封装在TCP隧道,因为TCP拥塞控制具有公平性,公平性;2.带宽的适配。

6.总结

上,善,若,水,下,流,至,贱!恶魔前面总是一张笑脸,天使背后总是一团糟粕。

标签: 无
返回文章列表 文章二维码
本页链接的二维码
打赏二维码
评论列表
  1. [...]8. TCP封装的隧道对于拥塞控制的意义[...]

添加新评论