文 / Alexey Ivanov
译 / 元宝
原文
https://blogs.dropbox.com/tech/2019/12/evaluating-bbrv2-on-the-dropbox-edge-network/
剧透警告:BBRv2比BBRv1慢,但这是一件好事。
BBRv1拥塞控制
自从“瓶颈带宽和双向”(BBR)拥塞控制技术发布以来,时间已经过去三年了。现如今,它已经被认为可以用在生产环境当中了,并且已经被添加到Linux、FreeBSD和Chrome(作为QUIC的一部分)中。在2017年发布的博客文章“优化web服务器以实现高吞吐量和低延迟”中,我们评估了BBRv1在我们的edge网络上的拥塞控制的效果,结果显示它非常棒:
在2017年BBR实验期间桌面客户端的下载带宽
自从那以后,BBRv1已经被部署到DropboxEdge网络上,我们也已经习惯了它本身存在的一些缺点。其中有一些问题最终是得到了解决的,比如Wi-Fi用户的网速明显变慢的问题。其他的权衡则都完全属于概念性的:BBRv1对基于丢失的拥塞控制的不公平性(例如CUBIC、化合物),BBRv1流之间的RTT不公平性,以及(几乎)完全不考虑数据包的丢失:
最初的BBRv1部署:某些设备的数据包丢失率>6%
当然,BBR开发人员(和IETF ICCRG)也非常清楚这些问题,并且积极地致力于寻求解决方案。确定了下列问题:
Reno/CUBIC流的低吞吐量与批量BBR流共享瓶颈值
不可知的损失;当瓶颈值< 1.5*BDP时,会有很高的丢包率
与ECN无关
高聚合度路径(例如wifi)的吞吐量较低
由于PROBE_RTT中的cwnd较低,从而导致吞吐量的变化
来看看BBR版本2
BBRv2的目标是解决第一个版本中存在的一些主要缺点,从对数据包丢失的不关心到没有足够的空间让新的流进入。此外,它还使用聚合/运行中的参数增强了网络建模,并增加了对ECN(显式拥塞通知)的实验支持。
随着BBRv2的即将发布,我们决定在DropboxEdge Network上试用一下,看看它是如何处理我们的工作负载的。但是在我们获得实验结果(和一些漂亮的图片)之前,让我们先看看免责声明和相关测试的设置。
免责声明
非低延迟的实验
这个实验针对的是高吞吐量的工作负载,而不是延迟敏感的工作负载。文中提到的所有TCP连接和nginx日志都经过了至少1Mb的数据传输过滤。
最后,我们可能会决定在数据中心内部部署BBRv2(甚至可能使用ECN支持)来支持RPC通信,但这不在本文的讨论范围内。
这不是一个单连接测试
这个实验是在单个PoP(存在点)中进行的,但是同时也是在数百万个连接的机器上执行的,因此不涉及单连接故障排除、tcptrace向下钻取或者tcpdump。接下来是摘要统计、Jupyter notebooks、pandas和seaborn。
尽管seaborn可以帮助创建漂亮的图形,但我在这方面还是失败了,因此对于糟糕的图形质量我预先说声抱歉。OTOH,至少不是xkcd样式=)
这不是实验室测试
这是在我们的edge网络上进行的一个真实实验。如果你想在实验室环境中测试BRRv2(或任何其他拥塞控制),我们建议使用github.com/google/transperf,它允许“在包括RTT在内的各种模拟网络场景(使用netem)中测试TCP的性能、瓶颈带宽,以及随时间而变化的监管速率”,例如:
transperf运行的示例
测试设置
我们在Tokyo PoP中使用了一组机器,并测试了以下几种内核/拥塞控制算法的组合:
5.3内核,cubic
5.3内核,bbr1
5.3内核,bbr2
4.15内核,bbr1
所有服务器都使用默认设置的mq和sch_fq qdisc组合。
内核基于Ubuntu-hwe-edge-5.3.0-18.19_18.04.2,所有补丁来自v2alpha-2019-11-17标记:
在ubuntu-hwe-edge-5.3.0-18.19_18.04.2上的一组BBRv2补丁
我们还应用了“tcp:Add TCP_INFO counter for packet received out-of-order”来简化合并和“[DBX]net-tcp_bbr: v2: disable spurious warning”来消除以下警告:
文章中的所有图表都是由ss -neit抽样中的连接级信息、proc中的机器级统计信息或web-服务器日志中的服务器端应用程序级指标生成的。
保持内核最新
较新的内核通常会给所有子系统带来相当大的改进,包括TCP/IP栈。
例如,如果我们将4.15的性能与5.3的性能进行比较,基于web服务器日志,我们可以看到,后者的吞吐量要高出约15%:
从Nginx的角度来看,4.15 vs 5.3文件下载吞吐量中位数
最可能的改进是“tcp_bbr:根据ack聚合估计调整cwnd”(解决了之前提到的Wi-Fi慢速问题)和“tcp:切换到提前出发时间模式”(我们将在稍后的AFAP部分进行讨论)。
最近的Linux内核还包括对新发现的CPU漏洞的缓解措施。我们强烈建议不要禁用它们(特别是在边缘上!),所以要准备好承受CPU使用率的打击。
保持用户空间最新
如果您使用的内核版本比操作系统绑定的版本要新,那么拥有最新版本的用户空间是非常重要的。特别是像ethtool和iproute2这样的软件包。
只需将ss命令的输出与旧版本进行比较:
$ ss -tie
ts sack bbr rto:220 rtt:16.139/10.041 ato:40 mss:1448cwnd:106 ssthresh:52 bytes_acked:9067087 bytes_received:5775 segs_out:6327segs_in:551 send 76.1Mbps lastsnd:14536 lastrcv:15584 lastack:14504 pacing_rate98.5Mbps retrans:0/5 rcv_rtt:16.125 rcv_space:14400
与新版本相比:
$ ss -tie
ts sack bbr rto:220 rtt:16.139/10.041 ato:40 mss:1448 pmtu:1500rcvmss:1269 advmss:1428 cwnd:106 ssthresh:52 bytes_sent:9070462bytes_retrans:3375 bytes_acked:9067087 bytes_received:5775 segs_out:6327segs_in:551 data_segs_out:6315 data_segs_in:12bbr:(bw:99.5Mbps,mrtt:1.912,pacing_gain:1,cwnd_gain:2) send 76.1Mbpslastsnd:9896 lastrcv:10944 lastack:9864 pacing_rate 98.5Mbps delivery_rate27.9Mbps delivered:6316 busy:3020ms rwnd_limited:2072ms(68.6%) retrans:0/5dsack_dups:5 rcv_rtt:16.125 rcv_space:14400 rcv_ssthresh:65535 minrtt:1.907
正如您所看到的,新的ss版本包含了来自内核的structtcp_info的所有优点,以及来自structtcp_bbr_info的内部BBRv2状态。这增加了大量有用的数据,我们甚至可以在日常的TCP性能故障排除中使用这些数据,例如,来自“TCP:sender chronographs instrumentation”补丁集的发送方缓冲区不足和接收窗口/缓冲区统计信息不足。
实验结果
低丢包率
首先,在启动BBRv2之后,我们观察到重传的大幅度下降。虽然还没有CUBIC那么低,但已经有了很大的进步。另外,考虑到BBR旨在忽略非拥塞引起的包丢失,我们可以说事情是按预期那样发展的。
Cubic,BBRv1和BBRv2的RetransSegs%
如果我们深入挖掘并查看ss统计数据,我们可以看到,BBRv2的丢包率比BBRv1低得多(请注意对数刻度),但仍然远高于CUBIC:
一个奇怪的实验结果是,BBRv2的连接丢包率大于60%,这在BBRv1和CUBIC机器上都不存在。仔细观察其中一些连接并没有发现任何明显的模式:数据包丢失大得离谱的连接来自不同的操作系统(基于时间戳/ECN支持)、连接类型(基于MSS)和位置(基于RTT)。
除了这些异常值之外,所有RTT的重传率都比较低:
不知为何,使用BBRv2的主机观察到的重新排序程度都较低,尽管这可能是较少动态分段引起的副作用:
吞吐量
从流量团队的角度来看,我们的SLIs edge性能之一是端到端的客户端报告的文件下载速度。对于这个测试,我们使用服务器端文件下载速度作为最接近的代理。
以下是从nginx的角度比较文件下载速度的结果:BBRv2与BBRv1和CUBIC的比较:
nginx吞吐量的中位数为95% ci(对于>1Mb的文件)
P75nginx吞吐量,95% ci(对于>1Mb的文件)
对于连接速率百分比较低的情况,BBRv2的性能更接近CUBIC,对于连接速率百分比较高的情况,它的性能开始更加接近BBRv1了。
连接级别的统计数据确认了BBRv2的带宽低于BBRv1,但仍高于CUBIC:
那么,是BBRv2较慢吗?至少在某种程度上是这样。那么,我们能得到什么回报呢?基于连接状态,实际上我们能得到很多东西。我们已经提到了更低的丢包(因此更高的“吞吐量”),但是还有更多其它的东西。
更少的动态数据包
我们已经观察到较少的“unacked”数据包,这是一个动态字节的良好指标。BBRv2看起来比BBRv1更好,甚至比CUBIC还要好一点:
绘制出RTT(往返时间)与动态中的RTT的关系图表明,在BBRv1情况下,动态中的数据量往往依赖于RTT,而RTT在BBRv2中看起来是固定的:
作为BBR的合著者之一,尼尔·卡德威尔解释道:
我看到的所有由于min_rtt值不同而导致不公平的情况下,其主导因素就是,对于BBRv1每个流都有一个cwnd基本上为2bwmin_rtt,这倾向于尝试在瓶颈队列中维持1 bwmin_rtt,这直接代表着较高min_rtt值的流将在瓶颈队列中维护更多的数据包,从而得到更高份额的瓶颈带宽。我知道在BBR框架中提高RTT公平性的最直接的方法就是去掉多余的队列,或者确保队列数量是独立于一个流的min_rtt估计。
接收窗口有限的连接
我们还观察到BBRv2连接比BBRv1和CUBIC的连接在“有限接收窗口”上花费的时间少得多:
我认为没有sch_fq的CUBIC会比BBRv1更糟糕。
较低的RTT
另外,BBRv2的RTT也比BBRv1低,但奇怪的是,它竟然比CUBIC高:
最小RTT与带宽之间的相关性
如果我们构建最小RTT与带宽的关系图,那么垂直波段表示的是用户到我们的Tokyo PoP的网络距离,而水平波段表示的是常见的互联网速度:
实验中所有BBR流(包括BBRv1和BBRv2)的bbr_mrtt和bbr_bw的散点图
这里有趣的地方是,BBRv1和BBRv2的MinRTT和带宽之间呈指数衰减关系。这意味着在某些情况下,RTT不自觉地限制了带宽。由于BBRv1和BBRv2之间的这种行为是相同的,所以我们对其进行深入的研究。尽管带宽可能被用户的接收窗口不自觉地限制了。
130+ 毫秒的 RTT波段代表跨太平洋的流量,因此很可能是GSLB未能正确地将用户路由到最近的PoP。在下面的博客文章中,我们将讨论如何利用RUM数据来避免这种情况。
改进CPU使用率
之前,BBRv1在接收到的每个ACK上更新整个模型,对于一个普通服务器收到的数百万个ACK来说,这是相当大的工作量。BBRv2有一个更复杂的网络路径模型,但它也增加了一个快速路径,该路径在应用程序有限的情况下可以跳过模型更新。理论上讲,这将极大地减少普通工作负载上的CPU使用率。
ACK快捷路径不是唯一的优化方法,请随意查看在BBR的IETF ICCRG 106演示中的完整优化列表。
然而,在我们的测试中,我们并没有看到BBRv1和BBRv2之间的CPU使用率有任何可测量的差异,但这可能是由于BBRv2启用了相当多的调试代码(目前:)
BBRv1vs BBRv2上的Idle CPU
如果要在启用了ECN的情况下测试BBR时,要特别注意CPU的使用情况,因为它可能会使GRO/GSO在高丢包情况下无法使用。
结论
在我们的测试中,BBRv2显示了以下特性:
对于网速较低的用户来说,带宽可以与CUBIC媲美。
对于网速较高的用户来说,带宽可以与BBRv1媲美。
丢包率比BBRv1*低4倍;但仍然比CUBIC高2倍。
传输中的数据比BBRv1低3倍;但略低于CUBIC。
RTTs较BBRv1低;但仍然比CUBIC高。
与BBRv1相比,RTT具有更高的公平性。
总的来说,BBRv2在BBRv1基础上有了很大的改进,而且在需要更高带宽的情况下,它更接近于Reno/CUBIC的完全替代。添加实验性的ECN支持,我们甚至可以看到数据中心TCP (DCTCP)的完全替代。
*减去0.0001%的异常值,且丢包率>60%。
附录A. BBRv2开发
开发在github.com/google/bbr上进行。bbr-dev邮件列表上正在进行讨论。
这里是BBR设计原则的列表(粗体表示它是新的v2):
留有余量:留出进入流的空间以便抓取
快速反应:使用损耗/ECN,适应现在的交付流程以保持流量平衡
不要反应过度:不要在每一次往返中都做乘法减少损失/ECN
延迟探查:探测器在一个时间尺度,以允许与Reno/CUBIC共存
稳健的探查:试着在切割est之前,探测到超出估计的最大bw,最大体积。
避免过度:在可容忍的动态中开始探测
可伸缩地增长:从一个额外的数据包开始探测;以指数方式增长以使用空闲容量
以下是迄今为止BBRv2开发中一些重要的里程碑:
BBR v2算法描述在IETF104:布拉格,2019年3月
BBR v2开源码发布在IETF105:蒙特利尔,2019年7月
BBR v2性能改进和修复IETF106:新加坡,2019年11月
附录B 显式拥塞通知
ECN是网络瓶颈通知发送方在用尽缓冲区并开始“丢尾”数据包之前放慢速度的一种方式。然而,目前,互联网上的ECN大多以所谓的“被动”模式部署。根据Apple公司的数据,74%以上最受欢迎的网站“被动地”支持ECN。在我们的东京PoP中,我们目前观察到3.68%的连接正在与ECN协商,88%的连接使用ecnseen标志。
如RFC“ 使用显式拥塞通知(ECN)的好处 ”中所述,在内部和外部使用ECN有很多好处。
经典ECN(aka RFC3168)的缺点之一是它对明确的拥塞信号过于规范:
Upon the receipt by an ECN-Capable transport of a single CE packet,the congestion control algorithms followed at the end-systems MUST beessentially the same as the congestion control response to a *single* droppedpacket.
...
The indication of congestion should be treated just as a congestionloss in non-ECN-Capable TCP. That is, the TCP source halves the congestionwindow "cwnd" and reduces the slow start threshold"ssthresh".
(并且有很好的理由,因为在显式(CE标记)和隐式(下降)拥塞之间的任何行为差异肯定会导致不公平。)
其他的RFC,例如“问题陈述和对显式拥塞通知(ECN)反馈的准确性提高的要求”,则使用了典型的ECN的低粒度,即每个RTT只能反馈一个拥塞信号。还有一个很好的理由:ECN的DCTCP(和BBRv2)的实现从其增加的准确性中获益良多:
M.Alizadeh等 数据中心TCP (DCTCP)
DCTCP对CE的自定义解释导致了对传统拥塞控制算法的完全不公平。
RFC8311,“放宽对显式拥塞通知(ECN)实验的限制”试图通过放宽这个要求来解决这个问题,这样实现就可以*地选择Classic ECN指定的行为之外的行为。
谈论ECN时,很难不提一下这个,就是在”低延迟、低损耗、可伸缩的吞吐量(L4S)”提议和“一些拥堵经验的ECN Codepoint(SCE)”草案背后的bufferbloat人们之间,一个代码点(半一点)的空间之间的IP报头也存在一个“拥塞通知冲突”。
正如Jonathan Corbet总结的那样:
这两项建议显然是互不相容的;每个都将自己的解释放在ECT(1)值上,并且会被另一个混淆。SCE方面认为,该值的使用完全兼容现有的部署,而L4S提案则由合适的指定协议来将其移交给私人使用,而这些协议与现有的拥堵控制算法不兼容。L4S的支持者认为,为了实现延迟目标,双队列架构是必不可少的;SCE似乎更关注于修复端点。
时间会证明,哪个草案(如果有的话)是通过IETF,与此同时,我们都可以通过部署AQMs(如fq_codel,cake)到我们控制的网络瓶颈中来帮助互联网。
还有一个RFC,即“关于活动队列管理的IETF建议”,其中有一整节是关于AQMs和ECN的部分。
附录C 越快越好
“从AFAP演变——关于时间的NICs教学”
范·雅各布森(Van Jacobson)曾做过一次关于计算机网络演变的伟大演讲,他说,在当今的互联网乃至数据中心,“尽可能快地”发送数据并不是最优选择。
你可以查看Van Jacobson的netdev演讲的幻灯片和视频。Julia Evans (@b0rk)和LWN.net (@BPismenny)提供的报道
这个演讲是一个很好的总结,说明了为什么可以考虑在网络层上使用定速和基于延迟的拥塞控制算法的原因。
公平队列调度程序
我们经常提到,我们所有的Edge框都使用Fair Queue调度程序运行:
$ tc -s qdisc show dev eth0
qdisc mq 1: root
Sent 100800259362 bytes81191255 pkt (dropped 122, overlimits 0 requeues 35)
backlog 499933b 124p requeues35
qdisc fq 9cd7: parent 1:17 limit 10000p flow_limit 100p buckets 1024orphan_mask 1023 quantum 3028 initial_quantum 15140 low_rate_threshold 550Kbitrefill_delay 40.0ms
Sent 1016286523 bytes 806982pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
2047 flows (2044 inactive, 0throttled)
6162 gc, 0 highprio, 43782throttled, 2716 ns latency
...
我们还提到,我们的主要目标不是公平排队本身,而是由tc-fq引入的速度。
早期的fq实现确实给TCP的RTT估计添加了一些抖动,这在数据中心内部可能会出现问题,因为它可能会增加RPC请求的p99s。在“tcp:切换到提前出发时间模型”中解决了这个问题。
下面是一个工作经历中的例子:让我们使用bpftrace来测量加入qdisc的数据包和从qdisc中退出队列的数据包之间的差异:
|qdisc-fq.bt是Brendan Gregg撰写的《BPF性能工具:Linux系统和应用程序可观察性》一书的补充材料的一部分。
附录D. Nginx吞吐量图
————————————————
版权声明:本文为CSDN博主「LiveVideoStack_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/vn9PLgZvnPs1522s82g/article/details/103856209
「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。