再次谈谈TCP的Nagle算法与TCP_CORK选项51CTO博客 - 超凡娱乐

再次谈谈TCP的Nagle算法与TCP_CORK选项51CTO博客

2019年03月04日08时03分34秒 | 作者: 巧蕊 | 标签: 算法,发送,小包 | 浏览: 2781

作业回放运用Open***传输虚拟桌面流量,终端上有显着逐帧刷屏现象,网络环境为百兆局域网。
剖析1.首先将Open***改为TCP形式,由于局域网环境下TCP和UDP不同不大,不会引起重传叠加问题。TCP的优点在于能够恣意蹂躏剖析,由于它的算法巨杂乱,假如换UDP,太简略了,没啥好调整的;
2.剖析进程不是本文的意图,直接给成果吧。减小发送/接纳缓冲区到MTU的2倍的姿态,减小MTU到1000以下,Open***加上tcp-nodelay选项,成果好了一些,可是仍是会刷屏,继续处理,终究承认这个问题搞不定,由于虚拟桌面地点虚拟机没装显卡驱动...(TMD我最烦那些出售眼中的天主告诉我让我能够处理一些不归于我领域的问题,比方在连信号都TMD没有的状况下能够确保手机疏通)
TCP啊TCP我懂TCP是由于我烦它!假如底子不理解就没有资历烦。TCP有超级多的参数能够调整,直接折腾就是了,我一贯以为,抓包东西是用来剖析数据的,而不是用来剖析TCP行为的,你能抓个包告诉我有没有启用Nagle算法吗?你能在客户端抓包剖析出来TCP timestamps导致的衔接被回绝吗?学习协议仍是要了解规划原理和该协议被规划和批改的前史,这样你才干知道它为什么会这样以及其时是什么原因导致了它这样,说实话,有时看看代码也是有优点的,可是看代码会让人简略钻进死胡同,比方一些非规范的东西一旦进入代码就会让人误以为是规范的东西,然后再看其它与之不同的完成的时分,先入为主的形象就会形象你的认知...
      总归,TCP很难,也很令人讨厌,一向觉得TCP规划的很好,可是开展的很乱。
网络运用率与许多小包许多人都把Nagle算法的意图了解为“进步网络运用率”,事实上,Nagle算法所谓的“进步网络运用率”仅仅它的一个副作用(Side effect...),Nagle算法的宗旨在于“防止发送‘许多’的小包”。Nagle算法并没有阻挠发送小包,它仅仅阻挠了发送许多的小包!固然,发送许多的小包是下降了网络运用率,可是,发送少数有必要发送的小包也是对网络运用率的下降,想彻底进步网络运用率,为嘛不直接阻挠小包发送呢?不论是许多小包仍是少数小包,乃至一个小包也不让发送,这才是进步网络运用率的正解!是的,TCP_CORK就是做这个的。所以有人说,CORK选项是Nagle的增强,而实际上,它们是彻底不同的两回事,初衷不同。
Nagle算法的初衷:防止发送许多的小包,防止小包众多于网络,抱负状况下,关于一个TCP衔接而言,网络上每次只能一个小包存在。它更多的是端到端含义上的优化。
CORK算法的初衷:进步网络运用率,抱负状况下,彻底防止发送小包,仅仅发送满包以及不得不发的小包。
关于交互式运用一向以来,人们有个误区,那就是Nagle算法会为交互式运用引进推迟,主张交互式运用封闭Nagle算法。事实上,正是交互式运用引进了许多的小包,Nagle算法所作用的正是交互式运用!引进一些推迟是必定的,究竟任何事都要有所价值,可是它更多的是处理了交互式运用发作许多小包的问题,不能将那么一点点为处理问题所支付的价值作为新的问题而忽视了真实的问题本身!
TCP的Nagle算法和推迟ACKNagle算法的操作进程请参看Wiki,它削减了许多小包的发送,实际上就是依据小包的停-等协议。在等候现已宣布的包被承认之前,发送端运用这段时刻能够堆集运用下来的数据,使其巨细趋向于添加。这是防止模糊窗口综合症的一种有用办法,请留意,模糊窗口指的是接纳端的模糊,而不是发送端的模糊,接纳端不论三七二十一得布告自己的接纳窗口巨细,一点点不论这会在发送端发作许多小包。可是发送端能够不模糊,你布告你的,我就是不发,你模糊我不模糊,你不断布告很小的数值,我不予理睬,我有自己的办法,直到收到现已宣布包的ACK才会继续发送,这就是Nagle算法的模糊抵抗计划。       医治模糊窗口综合症有两种方法,一种是“你模糊我不模糊”的方法,即上述的Nagle算法的方法,别的一种是“医治接纳端的模糊”的方法,其间一种机制是推迟ACK(还有其它机制,比方不发送小窗口布告等)。能够看出,这两种方法中都在企图削减包的发送量,二者异曲同工的处理了同一问题,关于发送方而言,不理睬接纳端的小窗口布告等于说不立刻发送小包,小包得以有时刻堆集成大包,关于接纳方而言,推迟ACK能够推迟ACK发送时刻,进而推迟窗口布告,在这段时刻内,接纳窗口有时机进一步(由于运用程序处理)扩大。独自了解这两种方法都是简略的,可是一旦它们混在一同运用,状况就会十分不幸!由于...
      Nagle算法和推迟ACK作用在方向相反的数据包和针对该数据包的承认包上,因而它们的作用力会相悖,成果就是谁也不能发包。就像一根绳子上拴两只青蛙相同,被对方控制谁也跑不了!要害点在于,小包的发送依靠于ACK,可是推迟ACK阻挠了ACK的即时发送,形成了相持状况。原本仅仅为了削减网络上小包的数量(再次着重Nagle算法以及推迟ACK的意图,留意,模糊窗口综合症仅仅网络上小包众多的原因之一!),却人为引进了许多的推迟!
      此处有一个通用的解说,Nagle算法的小包发送依靠于接纳端对小包得快速承认,因而接纳端对待ACK而言,应该朝着推迟ACK相反俄方向用力,即快速ACK;相对的,假如在接纳端启用了推迟ACK,发送端就应该不断发送数据包,不论是大包仍是小包(不考虑稍带ACK的影响),由于发送端现已不能盼望接纳端正常ACK数据包了,即发送端应该禁掉Nagle算法。以上解说背面的思维就是数据包和ACK包是相关的,力应该往一个方向使,一边拉另一边就要推,假如两头都拉,力就会抵消掉,堕入相持。不幸点或许说悲痛的当地在于,Nagle算法和推迟ACK机制都是“拉计划”!划船的人都知道,划桨手有两种座位布局,要么超同一个方向,要么面朝不同的方向,后者和TCP数据包和ACK很相似,要想船往前走,有必要朝一个方向划,尽管他们面朝相反的方向。
编程模型的影响在Nagle算法的Wiki主页,有这么一段话:
In general, since Nagles algorithm is only a defense against careless applications, it will not benefit a carefully written application that takes proper care of buffering; the algorithm has either no effect, or negative effect on the application.
可见编程模型对“削减网络上小包数量”的影响,弦外之音,Nagle算法是个有针对性的优化-针对交互式运用,不是放之四海而皆准的规范,要想有一个比较好的计划,别盼望它了,仍是运用程序自己搞定才是正解!要想Nagle算法真的能够削减网络上小包数量而又不引进显着推迟,对TCP数据的发作方法是有要求的,交互式运用是其初始针对的目标,,Nagle算法要求数据有必要是“乒乓型”的,也就是说,数据流有清晰的鸿沟且一来一回,相似人机交互的那种,比方telnet这种长途终端登录程序,数据是人从键盘敲入的,鸿沟根本上就是击键,一来一回就是输入回显和处理回显。Nagle算法在上面的场景中确保了下一个小包发送之前,全部宣布的包现已得到了承认,再次咱们看到,Nagle算法并没有阻挠发送小包,它仅仅阻挠了发送许多的小包。
      换句话说,所谓的“乒乓型”形式就是“write-read-write-read”形式-人机交互形式,可是关于Wiki中指出的“write-write-read”(许多的request/response形式俄C/S效劳就是这样的,比方HTTP)-程序交互形式,Nagle算法和推迟ACK拔河的后果就会被扩大,在“TCP的Nagle算法和推迟ACK”一节中我现已说了,这二者不能混用,这个咱们现已知道了,但那仅仅在TCP本身的原理上给与阐明,本节中说的是同一个问题,可是侧重于编程层面,可是却不是仅仅用setsocket将TCP_NODELAY设置一下或许关掉推迟ACK那么简略。
      有一篇很好的文章《TCP_CORK: More than you ever wanted to know》,文章说,Nagle算法关于数据来自于user input的那种运用是有用的,可是关于数据generated  by applications using stream oriented protocols,Nagle算法朴实引进了推迟,这个观念我十分附和,由于关于人而言,TCP登录俄长途计算机就是一个处理机,人期望自己的操作立刻展现成果,其形式就是write-read-write-read的,可是关于程序而言,其数据发作逻辑就不像人机交互那么固定,因而你就不能假定程序依照任何序列进行网络IO,而Nagle算法是和数据IO的序列相关的。实际上就算接纳端没有启用推迟ACK,Nagle算法运用于write-write-read序列也是有问题的,作者的意思是,无缘无故地引进了额定的推迟。
      莫非真的有这么杂乱吗?作者没有提出怎么靠编程把问题处理,可是Nagle算法的Wiki页面上提到了”尽量编写好的代码而不要依靠TCP内置的所谓的算法“来优化TCP的行为。再次引证Nagle算法Wiki上的那句话:
另一件作业In general, since Nagles algorithm is only a defense against careless applications, it will not benefit a carefully written application that takes proper care of buffering; the algorithm has either no effect, or negative effect on the application.
这句话引起了我对别的一件事的考虑,这件事就发作在上星期,由于公司搬迁全部处于紊乱中,无心作业,一个网络处理加速卡供货商来访,对方宣称他们的协议栈完成在用户态以进步功能,我起先对此观念不以为然,可是结合我的以上剖析以及后续的考虑,我发现这真的是一个打破:
当咱们什么作业都依靠内核的时分,或许咱们真的错了!内核不可控,为何不在用户态自己搞定呢。内核供给的是基础设施上的根本效劳,供给高端私家订***务会把整个内核拖垮!假如协议栈在内核完成(宏内核的风格),那么就在用户态办理TCP buffer,免除对杂乱TCP算法的依靠,假如协议栈在用户态完成,那就完成一个更好的类Nagle算法!
这件作业我预备再写一篇文章,现在回到《TCP_CORK: More than you ever wanted to know》
回到《TCP_CORK: More than you ever wanted to know》作者提到了一个观念,即write的语义,这背面的思维就是”全部皆文件“。已然全部皆文件,那就要为全部的IO都界说一套文件IO的操作集。咱们知道,UNIX开始将文件IO分为了两种,即块设备IO和字符设备IO,这个观念或许说哲学观念是具有划时代含义的,它带来了编程的简洁性,为程序员带来了一丝清新之意,那个时分不论是TCP/IP规范仍是BSD socket都还没有被提出,当网路协议栈成为规范的时分,作为一种IO类型,网络IO该归于块设备IO仍是字符设备IO呢?其时有两种观念,其间之一就是将网络IO从文件IO中独立成一个平级的IO类型,可是终究仍是BSD socket获得了成功,即网络IO也是一种设备IO。可是问题仍是在,网络IO究竟是归于块设备IO呢,仍是该归于字符设备IO?
      在答复这个问题之前,首先要为网络IO界说一种设备模型,没有设备模型,何谈设备分类?终究,网络IO的设备模型就界说为了packet,正如作者所说,网络IO对应的设备就是网络数据包(packet),用户运用程序经过规范的文件IO接口write将网络数据写入一个设备,该设备就是packet!现在剩余的问题不是这个packet何时真实flush到wire的问题,而是怎么生成这个packet的问题,假如数据能够继续堆集在一个buffer,然后生成一个packet,那么它就是块设备,假如数据来一个就生成一个packet,那就是字符设备。惋惜的是不论是BSD socket仍是协议栈,都没有规则究竟有没有这个buffer,因而,网络IO作为一个被特殊的类型,独立于块设备IO和字符设备IO之外,成为了第三种IO方法。因而咱们能够说,网络IO或许说INET族的socket IO,能够界说一个buffer作为socket文件IO接口到packet(作为一种设备)的缓冲,也能够不界说。界说与否取决于什么?取决于你怎么来解说网络!John Nagle从”小包众多会导致网络瘫痪“这个视角动身,发明晰Nagle算法,而另一些人从”buffer packet会引进推迟“这个视角动身,抵抗Nagle算法,这个争斗其实是没有含义的,其要害导火线在于”全部皆文件“思维遇到了网络IO时的为难。
      那么咱们是否能够答复这一问题呢?网络IO究竟应不该该在数据和packet之间有一个buffer?这仍是应该取决于packet究竟是一个字符设备仍是一个块设备。这个问题的答案取决于网络状况和数据接纳端状况,关于TCP而言,长肥管道的抱负状况下,packet就是一个字符设备,而关于在慢速网络上运用telnet登录的程序而言,packet就是一个块设备,buffer存在与否取决于许多的要素而不是一个要素,存在即是合理的,Nagle算法存在,可是不是让人乱用的。举个比方完毕本节,滚滚长江东逝水,顺江而下可行船,拦江切断储水可发电,究竟应不该该在长江上构建一个buffer,也是有争议的....
Linux的优化正如树立大坝存在争议相同,是否缓冲网络数据也存在争议,因而Nagle算法的完成并不存在一个哪怕是事实上的规范,更别提什么工业规范了。因而各家操作系统都有自己的完成,完成中存在有本身的风格。Linux当然也不破例,在数据发送的时分,会有一个tcp_nagle_check函数来判别是否应该将数据buffer起来,咱们看一下注释就理解了其完成要旨:
/* Return 0, if packet can be sent now without violation Nagles rules:
* 1. It is full sized
* 2. Or it contains FIN. (already checked by caller)
* 3. Or TCP_NODELAY was set.
* 4. Or TCP_CORK is not set, and all sent packets are ACKed.
*    With Minshalls modification: all sent small packets are ACKed.
*/
值得一提的是TCP_CORK选项和最终的Minshalls modification,咱们先看TCP_CORK,说起这个选项,许多人会把它和Nagle算法联系起来,实际上它们的联系并不是十分清晰,严格说来TCP_CORK是为了进步数据包的载荷率而引进的,而咱们知道,小包的载荷率十分小,所以感觉上好像是TCP_CORK和Nagle算法相关。实际上,CORK选项进步了网络的运用率,由于它直接制止了小包的发送(再次着重,Nagle算法没有制止小包发送,仅仅制止了许多小包的发送)。
      CORK选项在完成上仍是和文档中所说的有一些收支,比方,在超时状况TCP发送窗口勘探包的时分,会将buffer的包发送曩昔,咱们看下其注释:
/* A window probe timeout has occurred.  If window is not closed send
* a partial packet else a zero probe.
*/
背面的思维很简略,横竖也是要发送勘探包,跑不了了,平白仅仅发送一个勘探包,载荷率太低,是不是能稍带一些东西曩昔呢?答应的状况下,把buffer的packet带曩昔吧,尽管它们还没有buffer到一个full size的packet。假如说有些同学仅仅死抠full size的话就会很纠结,事实上,CORK的真实初衷是进步载荷率,进步网络运用率。关于CORK,最终要说的是,它仅仅Linux完成的一个选项。
      最终咱们来看一下所谓的Minshalls modification,这家伙对Nagle算法做了什么批改呢?很简略,尽管Nagle算法要求发送出去的packet被承认之后才干发送小包,可是依据Nagle算法的初衷,它仅仅是防止发送许多小包,那么为何不直接疏忽大包的承认呢?也就是说,只需求宣布去的小包被承认就能够继续发送小包了,这的确是一种优化,可是也会带来一些额定的作用,Minshall算法确保了只需一个小包在网络上,可是Minshall算法也或许会像机关枪相同突突突的继续发送小包(只需ACK继续到大),依照削减小包数量的初衷,它的确每次只发送一个小包,可是发送距离却短了...
跋文TCP太杂乱了,任何人的任何剖析都是片面的,你都能找出缝隙,由于关于TCP而言,其任何一个特性的参数调整都会对其它的特性,长肥管道是抱负状况,但在某些状况下却并非最好的状况,Nagle算法有时需求封闭有时需求敞开...唉,TCP啊TCP


版权声明
本文来源于网络,版权归原作者所有,其内容与观点不代表超凡娱乐立场。转载文章仅为传播更有价值的信息,如采编人员采编有误或者版权原因,请与我们联系,我们核实后立即修改或删除。

猜您喜欢的文章