令人躁动一时且令人不安的TCP BBR算法

虽然我在这个周六(2016/12/17)荒废了一天而毫无意义的加班,我依然要在次日把上一周的点滴记录下来。以下在2016/12/18下午19时之前的文章,全属周六通宵之作。
可以说,这个周末过得比较水。我已经30多个小时没有睡觉了。周六加班大半天,晚上跟同事打了两个多小时技术电话...你们能想象到跟同事电话里带着形而上的观点聊两个多小时技术,我们对工作该是多么负责啊!我并无意表达我要表现出很忙的意思,事实上我几乎从不加班,但这一次,不一样。
        BBR算法是Google的大作,既然我一开始认同了它,那就不能在遇到它不适应的场景时随意抛弃它,要想办法优化它。要像几年前搞VPN时的那种态度去对待BBR。本文的目的不是要把BBR算法拉下神坛,本文算是一个总结性的,然而点点滴滴的字里行间却充斥着我的不满。如果说谁能在30多个小时不睡觉之后还能写一篇浓浓鸡汤味的暖文,那是在把事情做成功之后的庆功宴会喝醉以后吧....现在,除了咒骂,别无其他。
-------------------------
Linux 4.9内核的发布,最令人兴奋的特性当属BBR算法了,这个算法的发布让4.9内核简直成了一个里程碑。在4.9内核发布之前,我就详细分析过BBR算法的诸多细节,我的感情色彩从推崇到平淡直到冷漠和咒骂,我个人在刚刚刨去了对BBR的无知而黄袍加身给它的光环后,从头来看,我应该在最初的“推崇”前面加上盲目两个字,是为“盲目推崇”。
在我盲目到一定程度而彻底迷失之前,我仔细研究了与TCP无关但与BBR相关的很多细节,包括骨干网拓扑,时下流行的几款Cisco设备的转发细节(比如Cisco Nexus 95xx系列),以及SDN网络的配置,发现BBR根本就不是一个独立的模块,它完全做不到像CUBIC算法那样的独立收敛,它依赖的外部环境太多太精细,以至于它完全不通用。如果你测试了BBR,并且结果还不错,就像Google的报告中显示的那般,那么恭喜你,你的网络环境与Google的无异,如果你的测试结果不达预期,那么同样恭喜,因为根本没人预期它的表现能有多好,庸人自扰之。Google的测试报告非常严谨,只是说“在....情况下,BBR针对传统TCP的加速比达到...”。
        你可知,这个加速比是路由器在摆脱了N加速比之后释放给BBR的额外恩惠,你知道路由器出口排队的N加速比是什么意思吗?我简单点描述好了,路由器的每个出口队列容量必须是其它所有N个入口处理带宽之和的数量级与线速系数的乘积(理论上队列容量要等于入口带宽之和,但考虑到线速转发,队列容量要远远小于这个值),这就是N加速比问题。目前骨干路由器交换机大多数是出口队列,这样N加速比问题就会带来一个很严重的后果,即BufferBloat!我们知道,骨干节点的带宽都是很大的,且节点的出入度都很高,N加速比问题带来的结果就是出口队列非常大(这就是深队列),然而如何保证每个入口只用其中的1/N呢?这就是各式各样的队列规则和调度算法的范畴了,这就是说,在队列规则和调度算法不区分五元组的情况下,深队列缓存很容易被误用!遗憾的是,骨干路由节点很少会关注五元组信息,虽然各种队列管理机制,哈希算法等宗旨都是为了保证“公平”,但是公平的原则是建立在信息量足够的基础之上的。大多数的队列缓存又是共享缓存,所以误用队列缓存的各种流量就非常多了。作为技术洁癖患者,我认为TCP亵渎了IP,你觉得呢?这是我恶心TCP的理由之一。
        比如说,由于运营商一般会对UDP流量进行策略化监管或者限速,目前,有一种非常简单的UDP双边加速的方式就是,仅仅将协议号由UDP改成TCP即可!而UDP允许一定程度的丢包,所以说,路由器交换机的AQM对其而言,就是刑不上大夫!
        SDN网络或者大型企业骨干网络相比上述的运营商骨干(包括分层的接入,汇聚,核心,跨BGP...),就简单多了。
        在SDN网络或者新建的大型企业骨干节点,N加速比问题几乎被排除了。为什么呢?因为这种网络的流量非常容易被调度到一个足够均衡的平衡点。虽然在拓扑复杂性上,骨干网是极其复杂的,然而在流量复杂性上,却又是十分简单,因此控制平面和管理平面可以设计的非常简洁,用以指导数据平面在上述平衡点附近的高效转发。
        BBR算法在此处发力!
-------------------------
可是在你身边又有哪个声称搞TCP的人会去了解上面那些事情呢?
        当然,我说这话有点偏见,因为我本身就喜欢上面说的那些路由器呀交换机呀等东西,并且持续了11年,我比较恶心TCP协议以及Socket之类的,并且恶心了11年,所以说在我的字里行间充斥着不公平的诅咒!
-------------------------
Linux 4.9发布了,大部分并不知所以然的所谓跟风者开始YY了,YY BBR多么多么神奇,多么有望取代CUBIC成为默认拥塞算法...YY它可以超过CUBIC几十倍...那不过是一组你看到的数据,到我这里测试说不定就是渣渣!我上半年也写过一个算法,在我的测试环境下可以秒CUBIC十几倍,可为什么它即便在我个人这里也销声匿迹了呢?
        我不喜欢把“场景”这个词用在网络上,我觉得用“属性”这个词更好。场景是可变的,而属性则是固有的。我来简单描述一下BBR适用于什么样子属性的网络。先说结论吧,BBR适用于稳定性比较好的网络。我以道路来做类比,就是两类,一个是高速公路以及城市快速路,一个是展现城市窗口的道路,总之就是秩序感比较强的那种。然而在我们的生活中,80%的时间我们会花在“最后一公里”的道路上,这是一个80/20原则!正是那最后一公里拖慢了整体的效率!
        BBR比较适合跑在从一个收费站到另一个收费站之间,或者沿着长安街从东单跑到西单,要么就是沿着世纪大道从陆家嘴跑到世纪公园,一旦拐到小胡同里,就分分钟成渣了。这并没有说BBR不好,就像从来都没有人说兰博基尼不好一样,但是买辆兰博基尼在胡同里开的,要么是为了装逼,要么就是傻逼。
        我来根据BBR的状态机画一幅其速度/时间的草图:

一旦发生带宽抖动,BBR将不得不承受“带宽无法充分利用”(带宽向上抖动)或者“保守导致激进”(带宽向下抖动)...不管怎么说,基于内部伺服器的策略都是一厢情愿的轮询做法,它的高效性完全建立在其对整个场景的充分理解基础之上,否则,BBR必须为自己的自行其是付出代价!
        温州皮鞋厂老板非常鄙视这种不知其所以然的盲目测试,这一点的认同使得我和温州老板成了朋友。还记得当年评估Intel 82599网卡特性的时候,我告诉过他们,到底是轮询还是中断,完全取决于你对流量属性的感知程度,你要充分测量流量的每一个细节!在这一点上,BBR看样子是做对了!然而,我腻了!
        温州老板这么周末要研究下BBR算法,另嘱咐我写一篇关于BBR的科普文章,我本来想答应,但是周末要加班,就只能拖延。我自认为我写一篇可以让任何人看懂的科普性的BBR文章并不太难,我相信自己有这个能力,但是最终,我还是只能拖延,我对温州老板表示抱歉。
        从上图可以看到一个值得优化的地方,那就是下面的函数:

static bool bbr_is_next_cycle_phase(struct sock *sk,
                    const struct rate_sample *rs)
{
    struct tcp_sock *tp = tcp_sk(sk);
    struct bbr *bbr = inet_csk_ca(sk);
    bool is_full_length =
        skb_mstamp_us_delta(&tp->delivered_mstamp, &bbr->cycle_mstamp) >
        bbr->min_rtt_us;
    u32 inflight, bw;

    /* The pacing_gain of 1.0 paces at the estimated bw to try to fully
     * use the pipe without increasing the queue.
     */
    if (bbr->pacing_gain == BBR_UNIT)
        return is_full_length;        /* just use wall clock time */

    inflight = rs->prior_in_flight;  /* what was in-flight before ACK? */
    bw = bbr_max_bw(sk);

    /* A pacing_gain > 1.0 probes for bw by trying to raise inflight to at
     * least pacing_gain*BDP; this may take more than min_rtt if min_rtt is
     * small (e.g. on a LAN). We do not persist if packets are lost, since
     * a path with small buffers may not hold that much.
     */
    if (bbr->pacing_gain > BBR_UNIT)
        return is_full_length &&
            (rs->losses ||  /* perhaps pacing_gain*BDP won‘t fit */
             inflight >= bbr_target_cwnd(sk, bw, bbr->pacing_gain));

    /* A pacing_gain < 1.0 tries to drain extra queue we added if bw
     * probing didn‘t find more bw. If inflight falls to match BDP then we
     * estimate queue is drained; persisting would underutilize the pipe.
     */
     // 如果这里的“||”换成“&&”,将会如何呢?
    return is_full_length ||
        inflight <= bbr_target_cwnd(sk, bw, BBR_UNIT);
}

就着这个细节,我想来谈一下BBR的抢占性。

BBR的问题在于对带宽变化的不敏感,所以可以看出在上图中两个红色椭圆处会损失带宽,一旦有新的空余带宽,BBR必须等到ProbeMore的增益周期才能发现,而在此之前,可能新的空余带宽已经被别的流抢占了。我们来看一下为什么BBR要在ProbeMore增益周期一次性达到最大的可用带宽,因为BBR在1/4的增益后,新的实际带宽马上就可以在下一个RTT反馈回来,简单点说,BBR的发送速率多了1/4,在一个RTT后,它会发现根据ACK反馈回来的数据计算出的实际带宽真的也增加了1/4,只要能持续收到“美梦成真”的反馈,BBR就会一直继续增速,期待继续可以“美梦成真”!

这一点可以看出,如果在ProbeMore周期,BBR的抢占性是很强的,只要增加的发送速率一直能带来增加的反馈速率,这个过程就一直继续,然而可能其它的数据流并不会等到BBR到达ProbeMore周期就把带宽抢完了!在ProbeBW状态下,ProbeMore只有一次机会,接下来会短暂的ProbeDrain,然后就是6个平稳的发送周期,大约会持续6个RTT的时间,在这段时间内发生的任何事情,BBR都无法感知!会发生什么事情呢?很简单,要么可用带宽增加了,要么可用带宽减少了,如果是减少了,在时间窗口内,以最大的带宽发送数据将会造成丢包,BBR并不识别丢包而降速,所以此时BBR的行为就会比较激进,直到新的ProbeMore之后退出后的ProbeDrain周期!问题在于,收敛到已经减少的可用带宽,需要多个RTT!这又是为什么?
        为什么不能像ProbeMore一样,一次性收敛到新的可用带宽呢?
        原因很简单,因为不管什么情况,只要你主动降速,ACK马上就能把降速的效果反馈回来,这是100%确定的,没有任何信号告诉你“降速已经够了”!所以说,每轮降速一次就是一个合理的选择,因此可以说,对于BBR而言,实际上是乘性增,加性减的!这种策略用于补偿其对带宽变化的不敏感性!
        因此,可以说,BBR的模型是一个探测并使用可用带宽的模型,所依赖是其精细测量出来的rate_sample数据,这不是一个自动收敛的模型,和Reno/CUBIC完全不同。在Reno/CUBIC那里,算法对诸如rate_sample的细节是完全无知的,仅仅依靠ACK Clock就可以驱动算法的运作,最终收敛到一个公平的平衡点。
-------------------------
我们再看本文中的唯一图示,发现点什么吗?如果你开着一辆车在高速公路上,你会体会到这幅图的深意。
        如果你的前车不违规,那么按照跟车距离200米来算,你的大部分时间都处在匀速状态,在不考虑限速120的前提下,你可能会隔一段时间尝试一下更快的速度,但是发现前车并没有提速的情况下,你会慢下来回归原来的速度,宗旨就是保持跟车200米。
        然而,如果你在胡同里开车,BBR的原则将完全失效!请参考上图来想象一下你在以下的道路上开车:上海嘉定区叶城路,仓场路,博乐路,深圳宝安区宝安大道,安阳市文峰中路...BBR并不是无级变速,它比较类似与换挡变速机制。加速快,刹车慢。
.........
如今,Linux 4.9内核的发布,BBR骚动了全场,然而令人悲哀!太多的连什么是TCP都不懂的人要求测试BBR,这让我感到复杂并且悲伤!
        座椅爆炸!经理爆炸!
        我的措辞表达了温州老板的内心,我的措辞表达了王姐姐的内心,我在写这些措辞的时候无时无刻不在想着跟小雨对骂的加班的2012年12月29日。
        如今,BBR令人躁动不安,把Google的那几个人推向神坛。我由于是国内首批接触BBR的那帮人,在4.9内核发布前就写了几篇文章,很多人给我发邮件,有大量要求加速网络的,有大量要求入职的(甚至包括我现在的公司同事...),有拉私活的,但唯独很少有技术交流的(略有一二,已经加为好友并交谈甚久),敢问你们懂BBR吗?4.9内核一发布,一窝蜂的全出来了,典型的XX拿来主义,XX拿数据说话!
        我敢说,BBR无法为你们大多数人带来可观的数据,因为Yuchung Cheng和Neal Cardwell也是揍一拳会趴下的凡人,也不是吃一口屎一口翔香的猛士!但是不可否认,Yuchung Cheng和Neal Cardwell比大多数人更了解自己的网络的属性,更知道SDN的细节,而这些正是TCP程序员所忽略的!如果不了解这些,那就是劣根性带来的悲哀!绝大多数搞TCP的程序员,喜欢掰扯,且根本不懂网络,然而显得装逼,我不屑为伍,以前我是据理力争,然而现在不了。
-------------------------
Linux 4.9发布了,让很多人躁动了,这让人不安!
        对于TCP拥塞控制策略,任何人说任何话都可以自圆其说,就像任何人在任何地点可以评论股市一样!不妄言,甚至闭口不言,宁愿充当哑巴是最明智的,但这并不意味着其它所有人都是智者!
        你可以拿BBR数据来炫耀,同时也可以来打脸,但这仅仅是你的数据,如果你不明白上图中的细节,那么,BBR对于你来讲,和CUBIC有区别吗?哈哈!我依然会保持沉默。
---------就像何勇在红磡演唱会时抹鼻屎到镜头后说的话一样,我说:我不在乎得罪所有人!
---------再次声明,我不在乎高效,我只在乎公平,这是演化论决定的,推荐一本我正在看的书《盲眼钟表匠》。

时间: 2024-10-23 05:44:30

令人躁动一时且令人不安的TCP BBR算法的相关文章

可以将TCP BBR算法模块化到低版本内核取代锐速吗

上周的文章引发了比较火爆的争论并带来了争议,我比较满意或者遗憾,尽管如此,如果有人真的能明白在文章的背后我真正想表达的意思,我也就深感欣慰了.还像往常一样,我花周末的时间来总结结束,写点技术散文,同时我希望能在技术上引发同样的争论.        在跟温州皮鞋厂老板聊天时,老板让我从非技术角度重新思考了Google的BBR算法.        很多测试似乎表明BBR的表现非常不错,虽不能保证包打天下,至少相比锐速而言,它是免费的啊,那么疑问也就随之而来了,既然BBR是免费的,且效果不错,那么那些

TCP BBR算法与Reno/CUBIC的对比

我一再强调,BBR算法是个分界点,所有的TCP拥塞控制算法,被分为BBR之前和BBR之后的(其实发现,这并不是我个人的观点,很多人都这么认为,所有想写本文探个究竟).当然这里的"所有"并不包括封闭的那些算法,比如垃圾公司Appex的算法,或者伟大的垃圾微软的算法.任何的算法都内含了一个进化的过程,CUBIC和Reno看起来非常不同,但是却属于同一个思想,因此可以说,CUBIC是Reno的高级版本(将一种锯齿换成另一种锯齿而已),事实上,TCP拥塞控制算法一直处在不断的改进之中,起初,R

TCP BBR算法的带宽敏感性以及高丢包率下的优化

bbr算法比较简单也比较容易理解,所有关于它的优化也就同样不复杂了.        请注意,任何优化都只针对特定场景的,根本不存在一种放任四海而皆准的算法.我们分析Google的测试报告时,比较容易被忽视的是其bbr算法的部署场景.如果可以完美复现Google的B4网络,那么测试结果应该就跟Google是一致的,但不得不说,bbr算法内置了很多的参数(目前的版本中是写死的),Google方面有没有调整这些参数是未知的.我们先看一下bbr算法是怎么利用空余带宽的.        bbr算法最终会稳

深夜聊聊Bufferbloat以及TCP BBR

这篇文章的写作动机来源于知乎上的一个问题,有人问既然Bufferbloat是个问题,为什么路由器的缓存还要设计那么大.起初,我也是觉得缓存越大越好,这个就像人们拼命比拼谁的电脑内存大一样,因为在一般人眼里,内存越大就越快!然而对于网络而言,恰好相反,内存越大,越让人不想归家.        酒店舒适,但只是路过,没人会把家装修成酒店的样子,家才是越大越好.        路由器设计成携带大缓存的设备,这是一个错误!路由器不该有那么大的缓存,然而TCP大牛当年的一个"AIMD错误决定"让

在Wireshark的tcptrace图中看清TCP拥塞控制算法的细节(CUBIC/BBR算法为例)

这是一个令人愉快的周末,老婆上周从上海回来,这周末小小幼儿园组织去坪山秋游,比较远,因此大家都必须早早起来,而我更加有理由起床更早一些来完成这篇短文,因为要出去一整天,如果早上起不来,一天都没什么时间了.        另外,最近有人问我,为什么我总是喜欢在技术文章后面加一些与技术毫不相关的话,我说,咱们小时候学古文的时候,那些古代的作者不也是喜欢在文章最后写一段毫不相关的"呜呼...""嗟夫..."之类的吗?人写文章总是有感而发,所以,点题总是必要的.也有同事问,

Vultr VPS安装开启TCP BBR提速工具 附安装BBR前后速度对比

最近,我们很多网友应该都看到Google开源TCP BBR拥塞控制算法(简称BBR),我们可以应用到常规的KVM和XEN架构的VPS.服务器中,用来提升服务器的速度.因为要涉及到内核的修改,Vultr中文网建议我们使用在一些非网站环境中的项目,比如搭建的上网工具据说有可以较大的提高速度. 在这篇文章中,我将利用Vultr VPS部署BBR工具,然后对比安装之前和之后的速度区别.看看是否有效的提高我们的服务速度,要是能提升,那最好不过,我们一起试试看吧. 第一.预先准备工作 1.鉴于内核的修改不确

从TCP拥塞本质看BBR算法及其收敛性(附CUBIC的改进/NCL机制)

本文试图给出一些与BBR算法相关但却是其之外的东西. 1.TCP拥塞的本质 注意,我并没有把题目定义成网络拥塞的本质,不然又要扯泊松到达和排队论了.事实上,TCP拥塞的本质要好理解的多!TCP拥塞绝大部分是由于其"加性增,乘性减"的特性造成的!        也就是说,是TCP自己造成了拥塞!TCP加性增乘性减的特性引发了丢包,而丢包的拥塞误判带来了巨大的代价,这在深队列+AQM情形下尤其明显.        我尽可能快的解释.争取用一个简单的数学推导过程和一张图搞定.       

TCP BBR 从开启到关闭:以 Debian 9 为例

TCP BBR 从开启到关闭:以 Debian 9 为例 开启 执行如下命令: echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p 执行lsmod | grep bbr.如果输出类似下面的内容,则说明开启成功: tcp_bbr 20480 0 关

(转)CentOS 7安装TCP BBR拥塞算法

TCP BBR(Bottleneck Bandwidth and Round-trip propagation time)是由Google设计,于2016年发布的拥塞算法.以往大部分拥塞算法是基于丢包来作为降低传输速率的信号,而BBR则基于模型主动探测.该算法使用网络最近出站数据分组当时的最大带宽和往返时间来创建网络的显式模型.数据包传输的每个累积或选择性确认用于生成记录在数据包传输过程和确认返回期间的时间内所传送数据量的采样率. Google在YouTube上应用该算法,将全球平均的YouTu