TCP自时钟/拥塞控制/带宽利用之脉络半景解析

0.说明

搬家公司的人很多都穿皮鞋!Whybr>

这个题目不是很明确,而且这个文章比较长,也算是我的一个阶段性总结,既然是总结,就不必为题目而纠结了。在端午假期的最后来做这个总结也实属不易(假期前两天加班,没有完成预期的计划,低落),记得很早以前写那篇《TCP协议疑难杂症全景解析》的时候跟现在一个心情。翻翻以前的记录,写那个的时候是2011年的7月初,小小才刚刚半个月,如今小小已经马上5岁了,时间过得真快啊,弹指一挥间!!回首过去的五年间,最累的时候是在2011年中到2014年初这两年半的时间,有了小小之后工作更加努力,然则一个产品做到了让人感觉遥遥无期的地步,好几次想离职换个工作,我可是个研发啊,事实上我那段时间学会了机器上架,也理解了更多的网络方面的更深的东西,付出嘛,总会有回报,这是必须的!无数个夜晚漫步在寂静的陆家嘴(陆家嘴作为整个中国的CBD怎会寂静为夜已深!),打不到车,从冬天到夏天,再到冬天…公司年终评奖的时候,大家都是拿数据说话,谁的数据好看谁赢,豪言壮语高谈阔论无卵用,我的数据当然也比较帅,只是让我获奖的不是研发运维方面的数据(人家都很棒!),而是出勤方面的,比如xx天加班,xx’次夜间出勤,xx”次节假日出勤…等等吧,我是最讨厌加班的人,却因为这个拿了个大奖,天大的笑话啊,然而这种尴尬的场景总是一再在我身上上演,也是崩溃又欲哭无泪啊!

        也是在那段时间,我学会了随时随地支起摊子就能工作这样的本事,因为我的时间在那段时间被打得很乱,一天在公司安心研发的时间几乎为0,跑用户现场,生产环境上现场编程,这压力得有多大,而且还跟内核有关,万一一个panic…上线了又要值守,之后又是各种会议,前向总结,后向计划,晚上八点从用户现场下班准备回家却又被领导叫回公司开会,开完会大半夜的又必须完成当日的决议…为此,我蹿坏了前台旁边的木头凳子…后来我占领了公司的一间会议室,起初我是在那搭测试环境的,几十台设备摆在会议桌上同时开机压测颇为壮观,我以测试修bug为由长期呆在那里,也不管什么辐射不辐射,噪音不噪音,久而久之,那里就成了我的独立办公室了,不外出的时候,呆在那里听着机器的轰鸣声敲着代码十分之惬意,外出的时候,地铁站,公交车,用户现场,机房,家里,哪里都可以展开工作,因为有项目津贴,没网络时我就用手机开热点…于是乎我忘掉了自己的工作座位,那已经成了垃圾堆,甚至有同事以为我离职了。两年多过去了,感觉自己成长了很多,虽然没有整块的时间做研发,但确实能力有了很大的提高,所以我还是很感谢那两年时间遇到的每一件事,每一个人的。
        为什么突发感慨说往事呢能是因为最近的工作与TCP有关,各方面场景包括来自各方的压力与那段时间类似吧,当然好处是现在不用外出了,也不会夜间出勤之类的了,最重要的是时间,比3年前充裕了很多。不管怎么说,软件硬件都在进步嘛。爆炸!
        低落中无论如何也不能让这个假期如此假惺惺地过去,所以狠下心来再搞半个夜晚,算是《TCP协议疑难杂症全景解析》的续吧!

让我们以一个问题开始吧!
TCP依靠ACK来维持一个时钟,该时钟驱动发送端数据的发送,问题是,发送端应该发送多少数据呢

TCP释义

TCP是一个端到端协议,其节点分布在全世界的每一个角落,彼此不知其它连接的存在,因此无法进行全局意义上的时钟同步来驱动合作式的网络行为,与之不同的是,IP层虽然是无状态无连接的,但却可以进行这种分布式合作,比如各种动态路由协议就是合作的,依靠各种交互进行同步。这就意味着,端到端的TCP协议必须完成并处理好两件事:

a).由一个自时钟来驱动自己的行为,比如发送数据,“停-等”等等,这个是通过ACK & 超时定时器(混合型自时钟)来实现的。
b).比如依靠反馈系统自适应完成与其它连接的合作关系,且这种关系必须是合作的,不能是抢占的,这个是通过拥塞控制来实现的。
本文以下的篇幅围绕上述a)和b)逐步展开。

声明

网络分析包括很多的元素,比如协议分析,性能分析,逆向,行为分析等,协议分析比较简单,性能分析则非常复杂,涉及到比如马尔科夫过程,泊松分布这类让大多数人望而却步的东西,因此本文不包括这些,仅仅分析TCP的行为以及这行为背后的原因。

1.端到端的滑动窗口机制

TCP是一个端到端的协议,它在设计上不考虑数据经由的中间网络,你可以将中间的网络抽象成一个以太构成的管道,拥有无限的容量,拥有极限的速度,那么理论上只需要在发送端和接收端之间进行交互即可,TCP采用了滑动窗口机制来做流量控制,这个我不再解释,能看到此文并且看完的,都是懂TCP/IP的,而滑动窗口则是TCP的基础中的基础。

2.现实的网络状况

这里说的现实指的是两种现实,一种是历史的现实,一种是当前的现实,或者还有未来的现实。在TCP/IP早期,带宽几乎是独享的,除了有些链路噪声之外,你可以将其想象成完全的以太。因此网络中不会存在拥塞,因此TCP作为一个纯粹的端到端协议,工作的非常好。
        时间进入到了20世纪80年代末,网络出现了拥塞,或者仅仅是有先见之明的猛人意识到了互联网将爆发,网络将遭遇拥塞,因此TCP不能再保持端到端的纯粹性了,它必须处理拥塞,即它必须可以意识到拥塞,并对拥塞做出反应,好吧,就是在这个时候,TCP引入了拥塞控制机制,并且全世界对这一机制的研究持续了将近30年。
        进入21世纪,几乎所有的大城市都遭遇了大城市病,其中最令人不爽的就是道路拥堵导致的各种限,限外牌,限号,…伴随各种限的就是人们的各种抢,抢什么呢然是资源!实际上,此时的互联网上遭遇了同样的情形,我记得很早之前在一本杂志上看到过有人预测互联网即将崩溃的文章,但事实上它依然在如此拥堵的环境下工作的很好。原因就在于TCP的拥塞控制机制是自适应收敛的,不需要任何机构的管理,就可以保持互联网的恒稳。总之,目前,TCP一切安好!
        时间即将进入未来,TCP在中国获取不再那么令人乐观,伴随运营商的限限限,以及BAT等巨头互联网厂商的各种垄断,人们连抢抢抢的权利都没有了,事实上,带宽都被巨头们抢光了。
        在我们的土地上,任何美好的约定都可以不被遵守,任何契约都可以打破。TCP在中国也同样。
        人们不必再遵守TCP的公平收敛约定,于是出现了超级多的暴力方案,这就好像在高速公路上我发现有人比我跑得快或者拥堵的时候,我任意变道并直接开车把前车撞了,然后打个电话再弄来一辆车就好了,因为我有钱,我有很多车,我不在乎成本,然而被撞的车可能是人家几年的积蓄…这难道不是一个道理吗么一个数据包发两遍甚至三遍,发生拥塞时保持大窗口,甚至忽略拥塞控制机制直接暴力发送…因为这是在中国,所以这种军备竞赛如火如荼的进行着,人们不需要懂什么TCP协议,甚至都不需要懂网络的基本概念,完全可以把这事做的很黄很暴力,因此,美国的作者所谓的互联网崩溃,应该说的就是我们国家吧…

3.平稳的ACK时钟

我们知道,TCP是一个持续的数据流,就像是水流一样,起码在设计上,理想情况下应该如此。如本文之首所述,TCP流的发送依靠ACK来驱动,如果TCP流的发送想保持连续,就依赖ACK会持续的到来,持续的ACK导致持续的TCP数据流,持续的数据流在接收端产生持续的ACK…
        从最简单情况开始,请忽略掉窗口,假设这个时候我只想设计一个持续的数据流发送的机制,没有端到端的流控,也没有网络拥塞控制,仅仅是一个持续的流,该是个什么样子呢

我觉得应该是下面的样子:

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

在上图中,我们已经知道ssthresh的值了,那么我们可以直接发送这么多的数据吗论上不是可以吗是说ssthresh就是链路的容量吗送这么多不是不会发生危险吗全正确!
        但是要知道,理论上一次性发送ssthresh的数据是建立在链路容量完全是同等均匀的时间延展容器组成的基础之上,容量随着均匀的时间会均匀拓展,然而现实中的端到端更像是上图中的漏斗结构,漏斗两遍对于相同的流量的时间流逝速率是完全不同的,为了平滑这个差别,就需要一堵时间墙来减缓时间流逝快的一方的时间流逝速率,这堵墙就是队列!!
        在我小的时候,那时即便是城市里的酱油也不是按瓶卖的,而是由酱菜厂的工人推着车子一边叫喊一边卖,你要买酱油的话必须自备酱油瓶,然后工人会用一个漏斗一勺勺地将酱油灌入自家的酱油瓶里,我简单的画了个图:

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

这时你还会一次性把酱油倒进去吗..
定性分析后,我们来定量化。还是上面那个图,我们假设漏斗的细颈容量和宽部分容量的和正好等于大勺子的容量:

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

使用慢启动的情况

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

但是从TCP的标准和实现上均可以看出,这个过程并没有在窗口达到ssthresh的2倍时停止。这是因为现实的网络中,没有任何可信的主动信号通知拥塞,连接清空等事件,而主流的方案恰恰就是通过丢包来意识到数据发多了这个事实的。更复杂的是,随着新连接的建立和清除,已有连接的可用带宽会非常波动,并非理论上的ssthresh的2倍这个关系。而这些,我将在下面说明。

2).避免拥塞-加性增,乘性减

刚刚第一个方面说的是理想和理论,这里我们回到现实!
虽然在理论上,ssthresh和剩余带宽之间有精确的2倍关系,然而实际上,很多值都是合理的,在同一个连接中,只要可用带宽是ssthresh的常数倍(为了闭合圈,常数肯定大于1)即可。
        这个我们中TCP公平性收敛图上也可以看得出来,只要是加性增(大约一个RTT增加固定的1),乘性减(系数无所谓,不一定是1/2,只要小于1即可),就可以收敛到公平。为什么要这样
        我们不得不再次回到存储转发设备队列的敏感性脆弱性话题上,但是不再用基于统计学的排队论这个调调来阐述,而是用一种更加容易被人理解的方式来说明。

        假设一个链路上带宽被多个连接共享,且非常平稳,我们可以说这些连接的总带宽与网络的负载相等,都等于链路带宽W,它几乎是一个常数,为了描述队列是多么的容易随着时间积累,我们假设在时间点t的时候,负载为L:

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

但是如果发生了拥塞,则:

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

看到了吗可是指数级的,你来猜想Beta有多大果它是一个小于1的很小的数,那么式子是可以收敛的,这也是设计存储转发队列长度设计的依据,然而如果发生了流量突发或者遇到了UDP,组播什么的,这个Beta就不是小于1的小数了,它可能大于1,直观上看这意味着某种积累,第一个时间点剩余了a没有处理,这个剩余的a会占用第二个时间点的一个空间,在流量不变的情况下让第二个时间点来不及处理的数据数量变成2,然后就是4,8,16…猛吧!如果排队论难以理解的话,这个应该很好理解了吧。
        怎么来的就怎么滚蛋,既然流量指数级飙升,唯一可以让整个流量指数级下降的就是所有连接同时按比例缩减流量!假设都是缩减1/2,则:

TCP自时钟/拥塞控制/带宽利用之脉络半景解析

TCP自时钟/拥塞控制/带宽利用之脉络半景解析
2).加性增(无反馈信号),乘性减(有反馈信号)
TCP自时钟/拥塞控制/带宽利用之脉络半景解析
4).乘性增(无反馈信号),加性减(有反馈信号)
TCP自时钟/拥塞控制/带宽利用之脉络半景解析

你可以很容易证明,加性增是唯一的选择!可以用数学证明,慢启动/加性增/乘性减是最优的方案,从控制论的角度,也可以分析出来慢启动阈值ssthresh的本质以及其与最终收敛带宽的关系。

        好吧,要结束本节了,总结一下,本节首先用ACK自时钟说明了如何闭合反馈线路,然后用排队论的另一个侧面阐释了必须要乘性减,最后用控制论阐释了在这个反馈系统中必然要加性增。

附:队首(HOL,Head of Line)拥塞

你知道队首拥塞吗时结账的时候,如果当前付款的人与收银员出现了纠纷,那么等待付款的人将会迅速排起长队,在高速公路上,如果有任意车辆发生了碰擦,后面很容易在很短的时间将队列延伸数公里远,这就是队首拥塞,就是说在一个连续的处理流中,由于前面的处理无法顺利进行,后面的流无法向前推进导致挤压排队,这也是时间墙在作祟!
        极端一点的例子,假设一个路由器以1000pps的线速运行,如果发生队首拥塞,包队列将以1000pps的速度迅速增长!早期的入口队列路由器总是面临这个问题,现在好多了。当时引入入口排队的目的是为了解决出口排队的N加速比问题的,而队首拥塞作为一个被忽略的bug被引入了,并不是作为代价引入的。这点要明白。

4.10.ACK时钟的丢失

如果ACK持续到来,会驱动数据的持续发送,我们上面已经很详细地讨论了这个ACK时钟如何启动以及如何工作,扯了很远终于把慢启动的本质揭露了,看来这个ACK时钟确实来之不易,慢启动结束后,TCP寄希望于拥塞控制可以动态适应带宽,因此ACK时钟的频率也会适时动态改变,比如收到了三次重复ACK,虽然很可能数据包已经丢了,但是既然收到了ACK,还是说明有数据包被收到了,这个ACK时钟依然存在,这只是意味着发送端需要采取应对措施了,数据还是可以发送的,毕竟时钟没有丢嘛。
        然而,ACK时钟确实可能会丢掉,比如:
1).数据包持续大量丢失,无法在接收端制造任何ACK;
2).ACK数据包大量持续丢失,无法到达发送端;
3).发送端持久不发送数据,无法在接收端制造ACK,此时网络状况可能已经异变。

总而言之,只要ACK收不到了,就说明ACK时钟已经丢了,此时需要另外一种机制来重新激活ACK时钟,这就是RTO超时定时器。它是一个外部的时钟,驱动ACK时钟丢失后的数据发送,因此每当发生RTO时,需要重新执行慢启动,因为慢启动是制造ACK时钟所必须的,理由不赘述。

4.11.影响拥塞窗口的因素

当然,网络拥塞可以影响拥塞窗口,除此之外,应用程序本身也会影响拥塞窗口的大小,比如发送端已经不造数据了,此时拥塞窗口变大有什么影响呢响就是制造突发!而网络中的存储转发节点最怕的就是突发,请参考我的一篇文章中讲的队列的脆弱性!如果已经暂时没有数据要发送,拥塞窗口却一边被接收端清空,一边又被RTT,ACK等反馈机制增大,一旦应用程序制造了大量数据,且对端也同时腾出了大量的接收缓存,这批大量的数据将会突发到网络上,造成严重的后果!
        RFC2861中有个叫做Congestion Window Validation(CWV)的机制,具体可以参见该RFC。
        另外值得注意的是,TCP发送端当前能发多少数据并不是由发送窗口决定的,而是由窗口与“在途数据”之差决定的,这样在发送端发送数据和收到ACK反馈之间形成一个流水,发送逻辑仅仅是补充一个差值,使得最终的将要发送的数据和“在途数据”之和等于拥塞窗口的大小。在Linux的拥塞避免实现中,会check以下的逻辑:

上述代码描述了在带宽利用恒稳的时候数据包守恒的情况,在拥塞窗口并不是瓶颈的时候,这个守恒将持续下去,in_flight是不会变的,当收到ACK的时候,会将in_flight减少对应的被确认的数据大小,这意味着可以再发出去这个多,如果为了补充被确认的in_flight将要发送的数据小于一个突发限额,那么在可能的情形下需要增加拥塞窗口以发送更多的数据,否则就不再增加拥塞窗口。这个逻辑保证了两点:
1).维持了网络中数据包的守恒;
2).在维持守恒的前提下避免了大量的突发。
我们想象一种情景,ACK到达的速率非常快,或者路径上暂时拥堵的地方突然放空,此时ACK大量的数据会使得in_flight突然变少了,从而在拥塞窗口中空出大量的空间,如果这个时候按照窗口滑动的理论把这些空出的部分全部用来发送数据,会有可能造成突发式的拥塞,因此此时需要在维持守恒的基础上制止拥塞,此时需要暂时停止拥塞避免的增窗过程,避免突发进一步加大。由于上述代码的控制,使得突发总是被维持在一个范围内。
        这是一个典型的负反馈系统,这也是一种ACK时钟自动调速的机制,这种时钟变速理论上是无级变速,缓慢进行的,然而受到中间存储转发设备的影响,流量可能会被整形,最终的效果就不是那么平滑了。 如果我们抓包分析一下TCP在高性能网络上的表现,就会发现,事实上其拥塞窗口/时间曲线已经不再呈现那种细细的锯齿状态了。其实我们也可以预期,开始的时候,增加窗口,增加到其制造的剩余突发首次变得大的时候,说明ACK的速率已经跟不上发送速率了,这是一种自适应的调速,此时窗口将不再增大,从未维持了平衡。
        这样做调速而不是一味的执行拥塞避免增窗是合理的,因为拥塞窗口只是用来描述当前的网络拥塞情况的一种手段,并没有积累容器的作用(就像带突发的令牌桶那样),网络拥塞情况会随着时间的流逝而变化,因此前一个时刻积累的拥塞窗口的值如果没有被有效利用来发送数据,将会被废弃。拥塞窗口是时间敏感的!为了避免由于对端通告的接收窗口过小而造成拥塞窗口多余的部分被废弃而突变,RFC2861将会让拥塞窗口在小于对端通告窗口的时候–此时将由通告窗口决定发送窗口,拥塞窗口紧贴着in_flight的上沿,差不多大一个可接受的突发量的样子。这个突发量在早期被定义为3,后来被定义为网络乱序度的值,在Linux最近的版本中,又被定义为3。

5.结语与布雷斯悖论

终于写完了,这篇文章可以说是不间断写完的,有感而发之后本来想写成一篇散文,可是写着写着却又成了不伦不类的半吊子技术随笔,不管怎么,终于是写完了,我是不是可以睡一觉了啊,喝瓶真露,然后做梦!做梦之前,在最后,我想再引出一个主题来,这就是布雷斯悖论。
        城市道路是一个再好不过的关于时间延展容器和空间排队容器的实例了,TCP/IP网络只是比它简单一点而已,你知道为什么吗
因为城市交通中的汽车司机(公交车,旅游大巴,班车等除外)都是自路由的,即选择哪条路是司机自己决定的,既然由自己选择,就会涉及到协作(博弈论中名词),既然是博弈就会有稳定和不稳定均衡之说,令人遗憾的是,城市交通中司机们的协作是不稳定的,因此就会出现一个悖论,路是越修越堵,越宽越堵,指示牌越多越堵!这既是布雷斯悖论。
        在TCP/IP网络中,所有的数据包没有自路由的机制(最近开始的主动网络可能会有自由选路这方面的机制),所有路径完全按照路由表来,即便一个数据包想从某条特殊路径通过,也是无助的,这就是源路由为什么不被大多数路由器接受的原因吧,一个端到端的机制无法自适应网络拥塞,源路由很可能会产生不稳定的均衡!然而,我们想一下,路由表是怎么生成的果是管理员手工配置的,那不存在任何问题,但如果是类似OSPF协议生成的呢种协议可以自定义路径权值,如果把拥塞状态也加权进去,会不会也会将流量导向同一处呢定会!但是那条路瞬间权值会降低…抖动在所难免,涉及到BGP的话,情况就更复杂了。虽然跟城市交通很类似,但却更简单,因为即便是动态路由协议,它也是全局考虑的,不会出现多方博弈的场景。
        那是不是意味着可以无休止地建设网络基础设施了呢也!实际上,TCP/IP上的博弈也超级多,运营商之间,TCP与UDP之间,P2P与UDP之间,组播,自治域之间…太多了,博弈无处不在。

6.后面的故事

关于OSPF,精彩之处可能比TCP还要多,如果加入BGP的博弈,那更是一道佳肴了,在局域网领域,关于CSMA/CD/CA,应该跟这个差不多吧,CSMA/CD的精彩在于其闭环,而不像TCP这样必须依赖外部时钟来触发丢失的事件。但是也不能因此而贬损TCP,毕竟TCP是一个端到端的协议,其范围是全世界的所有节点,而CSMA/CD/CA之所以可以闭环是因为它处理的仅仅是有限范围内的事件,这段范围内在物理定律可以hold住的前提下不会降低人们的期望【附:所谓的物理定律可以hold住说的是完全靠物理定律就能感知事件,完全不依靠类似TCP的那种虚假的启发式…
        物理定律包括但不限于光速,波叠加,干涉,衍射等,人们可以忍受的延迟一般不能超过半秒级,而CSMA/CD/CA可以依靠光速和波的性质在这么短的时间内探知一切,这就是其闭环的原因,如果我们看一下TCP,它有一个time_wait,默认2分钟,这远远超过了人们对网络事件到达率的期望,因此维护这个状态必须依靠TCP内部的状态机以及地球的周长!】,因此它成功了,以太网的故事,后面会继续!
网络三部曲,搞定了任意一个,你就是大拿,搞定了全部,你就是神!这三个我分别简述,排序按照分层模型从低到上:

1).以太网

绝对是近30年来网络技术风头浪尖上的佼佼者,屡次完败对手秒杀群雄,靠的就是成本和收益之间完美的平衡!目前以太网技术已经渗透到了跨区域数据中心,OverLay Network,城域网,甚至广域网…以太网的CSMA/CD开创了完美的反馈控制的先河,它的设计思路和很多后来的协议完全一致,这是根本正确的做法。

2).IP协议

简单,无状态,将复杂性留给了端到端,但却为整个网络肩负!分组交换网的功臣,最佳实践者!动态路由,策略路由,流量工程大行其道,综合服务完败区分服务。IPv4的问题由IPv6修正!

3).TCP协议

在IP为其减负后,一心一意地服务端到端,其QoS目前尚佳,没有衰老的迹象,然而在中国除外,这个我就不多说了,明白人自然明白,不明白的说了也不懂。就像女人的安全裤一样,其实薄薄的一层布料没有任何安全防御功能,既不避光也不防弹,如果有人不遵守规矩的话,他就撕烂那一层象征性的布料,没有谁能阻拦,安全靠的是一种道德精神而不是强制准入控制,这就是端到端!
        屏蔽了IP层之后,你什么事情都可以默默地干!比如,把拥塞窗口保持在1亿…

这个端午假期有点假!旋转升降座椅会爆炸!菊花残,满地伤,花落人断肠!任太妹,人太美,你妹骑马跨马背,大便骑沟便沟内!

                                                                      ———-写于2016/06/11 补充于2016/06/16

来源:dog250

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2016年5月14日
下一篇 2016年5月14日

相关推荐