当前位置: 首页 > news >正文

BBR 和 CUBIC 对长肥管道的不同反应

有个关于 CUBIC(等一众 AIMD-based cc) 和 BBR 在长肥管道中的行为比较挺有趣,它们的表现竟然截然相反:

  • CUBIC 流共存,RTT 越大,Goodput 越低;
  • BBR 流共存,RTT 越大,Goodput 越高。

前一个被看作是问题,后一个却从未有人提起。

已抛出问题,接着我先给出实验确认问题,然后再用数学短评。先给出一个配置脚本,它为两条 iperf 流分别配置了不同的 delay,目的是看它们采用不同算法共存时,RTT 对 Goodput 的影响:

# 为打向 5201 端口的流打标签 10
iptables -A OUTPUT -t mangle -p tcp --dport 5201 -j MARK --set-mark 10
# 为打向 5202 端口的流打标签 20
iptables -A OUTPUT -t mangle -p tcp --dport 5202 -j MARK --set-mark 20

tc qdisc add dev enp0s10 root handle 1: htb
tc class add dev enp0s10 parent 1: classid 1:1 htb rate 10gbit
tc class add dev enp0s10 parent 1:1 classid 1:10 htb rate 5gbit
tc class add dev enp0s10 parent 1:1 classid 1:20 htb rate 5gbit

# filter 1 关联标签 10 
tc filter add dev enp0s10 protocol ip parent 1:0 prio 1 handle 10 fw flowid 1:10
# filter 2 关联标签 20
tc filter add dev enp0s10 protocol ip parent 1:0 prio 1 handle 20 fw flowid 1:20

# 标签 10 的 5201 流时延 2ms,丢包 1%
tc qdisc add dev enp0s10 parent 1:10 handle 10: netem delay 2ms loss 1%
# 标签 20 的 5202 流时延 20ms,丢包 1%
tc qdisc add dev enp0s10 parent 1:20 handle 20: netem delay 20ms loss 1%

加载脚本前,先确认两条流天然公平:
在这里插入图片描述

然后加载脚本,测试 iperf 命令如下:

iperf3 -c 172.16.56.4 -i 1 -t 5 -C cubic -p 5201 &
iperf3 -c 172.16.56.4 -i 1 -t 5 -C cubic -p 5202 &
sleep 8
iperf3 -c 172.16.56.4 -i 1 -t 5 -C bbr -p 5201 &
iperf3 -c 172.16.56.4 -i 1 -t 5 -C bbr -p 5202 &

先看 CUBIC,预期是左边大,右边小:
在这里插入图片描述
再看 BBR,预期相反,左边小,右边大:
在这里插入图片描述

都符合预期。

先给出一个直观解释,可类比有漏孔管道里的水流,管道越长,它就越难被填满,除非用更猛的水流灌。亦可用蒸发类比漏孔,河流越长越容易被蒸干而成为内流河,这就是 CUBIC,而不被蒸干最终入海的河流全靠支流汇集带来的河水本身和涌动力,补充流量至少足以抵消蒸发流量,这就是 BBR:
在这里插入图片描述

若用数学描述上面的实验和这幅图上面的那段话,我实在不想描述了,但已经描述太多次,也不多这一次了。

先看 CUBIC,我统一用 Reno AIMD 来讲。一个 AIMD 周期内丢 1 个包,而 additive increase 的线性过程可以很容易算出一个 RTT 的平均流量:

1 2 W m a x + W m a x 2 = 3 4 ⋅ W m a x \dfrac{\dfrac{1}{2}W_{max}+W_{max}}{2}=\dfrac{3}{4}\cdot W_{max} 221Wmax+Wmax=43Wmax

进而计算出 1 2 ⋅ W m a x \dfrac{1}{2}\cdot W_{max} 21Wmax 个 RTT 的总流量:

N = 3 8 ⋅ W m a x 2 N=\dfrac{3}{8}\cdot W_{max}^2 N=83Wmax2

然后总流量除以总时间算出吞吐:

T = 3 8 ⋅ W m a x 2 R T T ⋅ 1 2 ⋅ W m a x = 3 4 ⋅ W m a x R T T T=\dfrac{\dfrac{3}{8}\cdot W_{max}^2}{\mathrm{RTT}\cdot \dfrac{1}{2}\cdot W_{max}}=\dfrac{3}{4}\cdot\dfrac{W_{max}}{RTT} T=RTT21Wmax83Wmax2=43RTTWmax

另一方面:

p = 1 N = 1 3 8 ⋅ W m a x 2 p=\dfrac{1}{N}=\dfrac{1}{\dfrac{3}{8}\cdot W_{max}^2} p=N1=83Wmax21

反解 W,代入 T,即可得:

T = α ⋅ 1 R T T ⋅ p T=\alpha\cdot\dfrac{1}{\mathrm{RTT}\cdot\sqrt{p}} T=αRTTp 1

其中 α \alpha α 与 AIMD 参数 a,b 相关。这个结论告诉我们 T 与 RTT,p 负相关,也就是下面来自 IBM Aspera 为了揭示 TCP 长肥管道缺陷的反面图示:
在这里插入图片描述

直观理解,丢包率 p 是一个标量 N 的倒数,表示管道内平均多少载荷丢 1 个包,而该载荷量就是 BDP,因此只要 p 一定,BDP 就一定,RTT 越大,Goodput 越小,BDP 这个物理量在此体现为一种 “矩”。AIMD 不适应长肥管道,这个衰减是无解的。

虽然吞吐率无解,至少公平性还可以缓解,自 Reno 以来,Loss-based AIMD 算法也一直致力于解决 RTT 公平性问题,围绕着 BDP 这个 “矩”,算法也非常直接了当,即 BDP 越大,Additive Increase 过程越快,理想情况下,线性达到最大丢包 cwnd 的时间为一个常量。无论是 TCP Highspeed 还是 TCP Scalable,都旨在像理想 Additive Increase 靠拢,让 “吞吐/丢包率” 的双对数直线更陡峭,也就更具扩展性。

BDP 是个标量,它只是个数量,单位是个,字节,比特都无所谓,在控制端,它体现在 Inflight 的观测和 cwnd 的计算,它并不体现任何作用力的细节,而 BBR 与此不同,它直接控制速率而不是量(有争议,但讲它时不评价)。

BBR 的发送速率 R 由以下公式决定:

R = G a i n ⋅ B l t B w \mathrm{R}=\mathrm{Gain}\cdot \mathrm{BltBw} R=GainBltBw

BBR 使用 Gain = 1.25,对它的期待如下:

  • 抵抗丢包:通过稍微超过瓶颈带宽的发送速率,确保即使在丢包的情况下,网络仍然能够充分利用可用带宽。
  • 避免过度拥塞:通过动态调整发送速率,但不至于过度探测,在发现空闲资源时避免网络进入拥塞状态。

设网络的瓶颈带宽为 BtlBw,丢包率为 p,BBR 的发送速率为 R = 1.25 × BtlBw,则在丢包率为 p 情况下,有效带宽 Effective_BtlBw 可以表示为:

E f f e c t i v e _ B t l B w = B t l B w ⋅ ( 1 − p ) \mathrm{Effective\_BtlBw}=\mathrm{BtlBw}\cdot(1−p) Effective_BtlBw=BtlBw(1p)

为确保网络能够充分利用带宽,需满足:

E f f e c t i v e _ B t l B w ≥ R \mathrm{Effective\_BtlBw}\geq R Effective_BtlBwR

即:

E f f e c t i v e _ B t l B w ⋅ ( 1 − p ) ≥ 1.25 ⋅ B t l B w \mathrm{Effective\_BtlBw}\cdot(1−p)\geq 1.25\cdot\mathrm{BtlBw} Effective_BtlBw(1p)1.25BtlBw

解得:

p ≤ 0.2 p\leq 0.2 p0.2

这个意思是说,只要丢包率不大于 20% 附近,即使存在丢包,BBR 也依然能有效利用带宽,也就是 BBR 论文里那个图(详情请参考 一张图里看 Reno,CUBIC 和 BBR):
在这里插入图片描述

排掉了丢包的影响,接下来看 BDP 如何影响带宽挤占。这也是非常明显的事。

RTT 越大,相同起点的 BltBw,它的 BDP 越大,1.25*BDP 越大,那么它在 Buffer 中的占比就越大,带宽占比通过 Buffer 占比体现,从而它挤出来的带宽越大,该带宽可快速被 Max-filter 记忆到下一个 Probe phase。
在这里插入图片描述

好比一个老胖和一个瘦子一起坐车,一开始他们屁股接触椅子的面积差不多,但越往后老胖占地越大,并不是老胖故意挤,而是因为他体重大,车子晃动传递给他的力足以挤压更多空间,从而公平承载他的体重,如果总空间一定,两人体重的比例就是他们占用空间的比例,其实两人都觉得很挤。

所以,我曾经也对 BBR 的 RTT 做过一些改动,详见 BBR 的 RTT 不公平。简单讲就是让 gain 与 RTT 负相关,但又不至于和 BDP 做乘法时把 RTT 量纲消掉,一个典型的做法(不唯一)就是用 sigmoid 函数归一 RTT 的函数:

f ( R T T ) = 1 1 + e − R T T f(\mathrm{RTT})=\dfrac{1}{1 + e^{-{\mathrm{RTT}}}} f(RTT)=1+eRTT1

为了将 gain 限制在 1.10 到 1.50(恰好包含 BBR 默认的 1.25) 之间,且将 RTT 约束在 0 到足够大,要对 sigmoid 函数做指数变换和线性变换以求解参数,最终得到:

g a i n ( R T T ) = 0.7 + 0.8 ⋅ 1 1 + e − ln ⁡ ( 1 + R T T ) , R T T ∈ ( 0 , ∞ ) \mathrm{gain}(\mathrm{RTT}) = 0.7 + 0.8\cdot\dfrac{1}{1+e^{-\ln{(1+\mathrm{RTT})}}},\mathrm{RTT}\in(0,\infty) gain(RTT)=0.7+0.81+eln(1+RTT)1,RTT(0,)

当然,1.10 和 1.50 是拍的,1.05 到 1.25,1.25 到 1.75 都可以,拟合最佳效果的实际数据为准,调参可借助 AI。

很幸运,由于指数变换重新映射定义域,出现了 log 和 e 互逆,于是 gain 的表达式可进一步简化为简单函数:

g a i n ( R T T ) = 0.7 + 0.8 ⋅ R T T + 1 R T T + 2 \mathrm{gain}(\mathrm{RTT})=0.7+0.8\cdot\dfrac{\mathrm{RTT}+1}{\mathrm{RTT}+2} gain(RTT)=0.7+0.8RTT+2RTT+1

或许还可以对 RTT 增加一个相乘的参数,该参数能让函数收窄或放宽,视 RTT 的分布而确定,如果 RTT 比较稠密集中(方差较小),那么 gain(RTT) 倾向于围绕期望值收窄,反之则放宽,效果如下:
在这里插入图片描述
总结,没有哪个描述比下面这两个图更能直击 CUBIC 和 BBR 的本质了,CUBIC 的的视角是丢包事件,以丢包分割行为,BBR 的视角是资源利用率,以资源分割行为:
在这里插入图片描述

配图竟然露脸了…

浙江温州皮鞋湿,下雨进水不会胖。

相关文章:

  • 使用请求调用本地部署的stable-diffusion接口
  • 从零开始实现 C++ TinyWebServer 处理请求 HttpRequest类详解
  • 3D引擎:Three.js有什么有什么优缺点?
  • 数据人的进阶之路:四年数仓实践与成长思考
  • Elasticsearch + Docker:实现容器化部署指南
  • SpringBoot3使用CompletableFuture时java.util.ConcurrentModificationException异常解决方案
  • 优先级与环境变量的艺术:驾驭 Linux 系统的核心
  • Vue 入门到实战 五
  • Mac | Excel | 列数改为和行数一样用数字表示
  • MyBatis-Plus(SpringBoot版)学习第一讲:简介入门案例
  • Rocky9.2 编译安装Intel系列无线网卡驱动
  • RK3568 I2C底层驱动详解
  • 查找单入口空闲区域[A卷-hw_od]
  • 博弈论中的均衡精炼:完美贝叶斯均衡、序贯均衡与颤抖手均衡详解
  • 定义时钟约束
  • 游戏引擎学习第176天
  • leetcode699-修剪二叉搜索树
  • Agent:大模型中的智能“函数”
  • 【Vue3入门1】02- vue3的基本操作(上)
  • 【商城实战(57)】商城数据迁移与升级实战:开启电商新征程
  • 明星站台“胖都来”背后:百元起录视频,20万可请顶流
  • 戴维·珀杜宣誓就任美国驻华大使
  • 外交部:中方和欧洲议会决定同步全面取消对相互交往的限制
  • 中俄合拍电影《红丝绸》将于今年9月在中国上映
  • IPO周报|节后首批3只新股本周申购,色谱设备龙头来了
  • 国铁集团:铁路五一假期旅客发送量累计已超1亿人次