正文
很多人会认为一个好的TCP拥塞控制算法会让连接加速,这种观点是错误的,恰恰相反,所有的拥塞控制算法都是为了TCP可以在贪婪的时候悬崖勒马,大多数时候,拥塞控制是降低了数据发送的速度。
我在本文中会针对近期跟业内朋友之间的聊天记录,总结出三言两语。
TCP拥塞控制的终极目标绝对不是加快数据发送的速度,这种理解非常自私且肤浅!它的终结目标是在公平占有带宽的前提下无限度提高带宽的利用率!
如果你只关注一个独立的TCP连接本身,那么你也许永远都不可能设计出什么比较好的算法,但如果你不从一个独立的连接入手,貌似更加虚无飘渺,毕竟你能拿到且驾驭的只有一个连接!
考虑一个进程调度器的设计,从2.6.23开始,大家普遍认为Linux调度器迎来了一个新的阶段,即CFS阶段,相比之下,O(1)调度器仅仅像是一个过渡,而之前的O(n)调度器就略显初级了。当时我也关注了这个新调度器好一阵子,正如我这段时间关注TCP BBR一样...So,我们来看一下CFS到底好在哪里,以至于它可以占据Linux默认调度器这头把交椅。
首先我们反问,CFS让进程运行的速度更快了吗?非也,有点经验的都知道,对于追求高吞吐的环境,CFS反而让进程运行的速度更慢了。比较肤浅的认知角度,一般很容易将“好”和“快”紧密联系在一起,但事实上,站在更高的层次,你看到的将不再是一个独立的进程,而是一整机器里面所有的进程!CFS到底好在哪里?
从其名字上就可以看出,其好处在于“完全公平”!它治疗了O(1)调度器中几乎所有的不公平调度导致的症状,比如IO消耗型与交互进程之间的抢占与饥饿问题,比如调度粒度问题,等等所有这些问题,引入一个虚拟时钟后,公平性得到了非常精确的度量,这些问题最终得到了解决。从开始到最后,没有任何独立的进程“被加快了运行速度”!
最终,CFS让所有进程在公平持有CPU时间的前提下,让CPU尽可能满负荷运转,即提高了CPU的利用率。整个过程没有毛刺,非常平滑。
----------------------------------------------------
间中,我们来看看平滑代替毛刺的好处,眼睛只要直视就是那么的帅!《 德国佬又火了!奥迪终于把球形轮胎造了出来…》!
----------------------------------------------------
现在回到TCP本身,BBR和当年的CFS一样,引起了众人的关注。我想我已经引出了“如何设计一个好的TCP拥塞控制算法”的思路了。
站在全球互联网上空往下看,你看到的是所有的TCP连接,而不仅仅是你的机器上建立的那一个或者那几个。这就是格局不同,你的偏见自然也就消除了。上海自然要和北京竞争,但北京不这么看,不管哪里好了,都是它北京的,不是吗?如何让所有的TCP连接公平共享全部的互联网带宽,是TCP拥塞控制算法的根本!注意两个关键点,其一,公平地共享,其二,尽可能全部的带宽。
这个问题是一个世界难题,没有进程调度器那么简单!
进程调度器是作用于一个CPU的,或者简单点说,作用于一台机器。这台机器就在你的手上,你,也就是调度器的设计者完全可以看清楚当前机器里发生的一切,一切不公平症状,一切浪费现象可以让设计者尽收眼底,你可以强制性拿一个进程的资源给予另一个进程,你也可以杀死过于贪婪的进程...对于TCP而言,根本没有一个可以站在全球互联网往下看的高人,TCP拥塞控制是完全分布式的,每一个设计者都只能看到自己机器上的那一部分连接!
然而,TCP拥塞控制之所以如此难并不是什么所谓分布式导致的,其实分布式一点也不难,难点在于TCP拥塞控制总是被误解,所以说在设计算法的时候,稍不留神就会南辕北辙,本来是避免拥塞的,实际上是添堵的。
为什么会被误解?其实凯撒早就说过,人们总是看到自己希望看到的。这句话还有另一层意思,人们乐于把自己看到的局部当成所有。人们可以一眼看到一整机器的进程,所以设计出一个好的进程调度器是很容易的,所以CFS出现了。但是大家看不到所有的TCP连接,大家看到的只是自己的TCP连接,所以大家只能臆测,我好,你也好。至于算法是否添堵,可能完全不是出于恶意,而完全是目光的短浅和格局之不高导致的。
一个正确的,且好的TCP拥塞控制算法应该是顾及所有的连接的,如果TCP不够快,那就应该让所有TCP都提速,这点体现了带宽利用率的提高;如果TCP已经足够快,那任何连接都不能更快,这点体现了公平性。换成人话非常简单,如果你觉得开车走省道慢,那就上高速,如果你已经在高速公路上,请不要变道超车。
多么简单的道理,可还是能看到道路上变道超车的,我可能表达有问题,是所有的司机都在玩变道超车,如果让这些人来设计TCP拥塞控制算法,会好到哪里去呢?不幸的是,世界上TCP单边加速玩的最火的那批人,和这批中国好司机是同一批人,无论什么资源,唯一的目标除了抢,还是抢。
其实,我并非一个道德说教者,说什么人人为我,我为人人的算法才是一个好的算法,说的就好像我自己做到了似的...
我是被两位大师骂了才知错就改了,其实我也走火入魔过...
前一段时间吧,我修改了一个拥塞算法,呈给一位大师评解,姑且叫大师1吧,值得"炫耀"的就是我这个算法非常快,甚至比BBR还要快,但是被恶损了一顿,我的算法“竞赛肯定第一”,但是却“不负责任”...这种是毁人品的算法。后来,我试着让两个或者多个运行同一个算法的流一起传输数据,果然...一些流会瞬间把剩余的流带宽压榨到0!连敌友都不分了,简直就是流氓算法啊!这个算法从此也就阅后即焚了,完全不可用。
...
如果这还不算,那么另一位大师2则彻底让我觉得自己根本就狗屁都不懂。
这位大师在国外,跟我有时差,且能读中文但不写中文,我与之相反,我是能读英文但写起来费劲,所以只能邮件交流。主题还是拥塞控制,我由于急功近利只是问了“怎么让TCP数据发送速度更快”这样的问题,答案很简单,忽略拥塞控制并补偿性重传即可,然后我就写了一个“忽略拥塞控制的拥塞控制算法”,并且挑衅般的作为回应。然后的邮件里就出现了fxxk词汇,还有suck...说我根本就不懂基本的原则,并力劝我辞去工作回家仔细学习和思考。我都快哭了。
...........
大师2的教导在大师1之前,但是大师1给了我具体怎么做的方向和方法,我除了发自内心的感谢之外,能做的就是写一些“抨击TCP拥塞控制算法”的文章来把人人为我,我为人人的基督教理念传递给更多的人。出于对两位大师以及各路朋友的尊重,我不会贴出与之相关的代码,邮件原文以及聊天记录,消化加工后的理念,由我这里直接始发。
BBR
本文的最后,我通过BBR算法稍微聊一下什么样的算法是正确的算法。
BBR和当年的CFS一样,这个我已经说过了。但是BBR目前仍处在比较初级的阶段,起初呢,我认为它的问题在于:
1.收敛太慢,即不会即时降速降窗,而是要在几个RTT内完成;
2.向上探测太迟。难道问题1是对这个的补偿也说不准;
3.大BDP缓存下的抢占性有待商榷;
4.BBR依托的SDN基础设施...
...
可以看到,这种最初的领悟体现了我个人多么深厚的技术功底。然而后来,经大师指点,我才发现,原来BBR的最大问题在于,它引入的新拥塞控制框架很容易被误用,具体的请参见 http://blog.csdn.net/dog250/article/details/54754784
如果几个三流的比我还差的人使用新框架写算法,那么互联网崩溃指日可待,幸运的是,即便崩溃,也只是国内的互联网崩溃,在这个领域,国外的月亮就是圆的,毕竟人家比我们受教育程度更深,懂得博弈理论,即便从自私者的角度来看,损人不利己的事情也是做不来的。值得注意的是,有知识不代表有文化,我一直觉得国内的大学其实就是技校,特别是华中科技大学,几乎是定向给华为,BAT等巨头培养高级技工的。
回到BBR。对于BBR带来的新框架,最严重的是,之前有人拼速度拼重传的时候,会有prr降窗,这点是不受算法模块控制的,现在好了,直接写个回调,完全绕开了降窗,大家都去添堵去了TCP设计的原则层面,RFC里貌似也把公平性提到了至高的地位。因为如果不把公平性作为基本原则,那么整个环将不是闭合的,带宽资源早晚会用尽,此时盲目的AI非MD过程将会促使大家都想往前抢,最后谁也过不去,如此一来,互联网将完全不可用!基于这点,所有搞“TCP单边加速”的个人和厂商都是在做钻空子的坏事,其出发点就是错误的。当然,这类厂商的出发点往往不是TCP层面的,而是业务层面的,这倒是无可厚非,毕竟不是一个领域,我也无权过问太多,TCP对于它们而言只是工具,真到哪天互联网崩溃了,他们还是会用卡车运硬盘的方式来进行数据传输的,到时候,高速公路上堵的水泄不通的运硬盘的卡车与TCP一样,也只是个工具,而已。
----------------------
怎么样的做法是正确的呢?
先来介绍一个君子算法,即LEDBAT算法,可以看看 http://www.rfc-base.org/txt/rfc-6817.txt,其wiki是 https://zh.wikipedia.org/wiki/LEDBAT
它的思想在搞“加速”的那帮人看来,其实有点搞笑,它的存在是为了填补CUBIC之流不Bloat Buffer时候的空隙的,一旦有其它流量造成了排队,LEDBAT马上腾地方退让。这种算法是应该被“加速者”第一时间抛弃的算法,但是它在iOS和Win10里却大行其道,LEDBAT主要用于软件更新,这种事一般可以在后台默默进行,优先级比较低,所以发明一个后台静默的君子式LEDBAT算法,实则是在提高带宽利用率上无所不用其极啊,然而这个算法又不会跟其它的流量争抢带宽,丝毫不会应该高优先级流量的公平性,难道不是很帅的算法吗?LEDBAT在表达的是,你们去前面堵着去吧,我没你们重要,我慢慢走就行。。。
BBR不是君子式算法,它是要参与公平竞争的,我不主动欺负人,但是被人欺负,我不会怕事的,因此BBR在LEDBAT上增加了Probe More的过程,同时,与LEDBAT退让不同,BBR将其改成了轻柔缓和的Drain Less。
所有这些都不是最近刚刚出现的,在此之前,Vegas算法则代表了一种正确的做法,它最终没有上位是因为Vegas部署有个前提,那就是同一时间全部部署成Vegas,然而这是不可能的,只要有Reno或者CUBIC在,Vegas的“正确做法”就会吃亏。现实就是这样,劣币驱良币,CUBIC明明是错误的算法,但因为它可以利用率很低但很简单的方法快速收敛到可用带宽,所以就一直是大家认可的算法,所有人都在默默忍受着Bufferbloat,而这个问题带来的额外排队延迟会大大降低交互式TCP连接的交互体验,同时严重影响实时性的协议,比如NTP之类。
CUBIC是一定会堵路的,Buffer被堵了之后,交互应用的数据就会被排队,时延增加,交互性自然下降。
我一直好奇的问题是,为什么Reno,CUBIC之流在经过慢启动之后的AI增窗过程叫做拥塞避免,相反,这种盲目的一路走到黑的增窗方式一定会导致拥塞的,即拥塞不可避免。这个过程是玷污了“拥塞避免”这个词呢,还是说仅仅是一个定义呢?下面的一篇文章给出答案,现在的时间是周六早上7点半,该睡一会儿了。
写在最后的序:
“昨夜入城市,归来泪满襟”的那是傻逼,自己不养蚕便是了,干嘛嫉妒别人穿丝绸。
今天又是周末,又可以半夜起来折腾,本文写作开始于五点半,完成于早七点二十,在此之前,我花了一个小时时间读了《卢比孔河》之25页,再之前的一个小时,我看了一些关于道路规划的东西,主要在令人不安的电脑上...现在,本来我想睡一觉,然而睡不着,就想去登高望远,只可惜旁边的山都太矮小了...自从甘孜归来,深圳的山就成小土堆了...实际一点,去买菜,做饭才是解决之道,做什么饭呢?哈哈,重庆带来的老火锅!
----我希望你能看到这篇文章。