西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页 → 业内动态 → 业内资讯 → 拥塞控制原理:BBR凭什么把跨境下载速度翻一倍

拥塞控制原理:BBR凭什么把跨境下载速度翻一倍

相关软件相关文章发表评论 来源:本站整理时间:2026/11/2 20:50:11字体大小:A-A+

弱网管家v1.0.2 网络诊断优化
  • 类型:系统工具大小:15.0M语言:简体中文 评分:10.0
  • 标签:
立即下载

去年有一台跑在美西机房的机器,5M 带宽,月付三十多块钱,业务上就是跑个静态资源加一个接口。带宽买的明明是 5M,可实际下载速度长期卡在 600KB/s 上下,换了线路、换了机房、连商家都换了一家,还是那个速度。一开始所有人都怀疑是带宽被限速了,直到我把 sysctl net.ipv4.tcp_congestion_control 的值从 cubic 改成 bbr,同一条命令、同一台机器、同一份测速文件,速度直接干到 1.2MB/s 以上。带宽还是那个带宽,线路还是那条线路,唯一变的是内核决定「往网络里塞多快」的那个算法。

这件事让我意识到,很多人对「带宽不够」的理解是错的。带宽是管道,拥塞控制才是水龙头开多大。管道再粗,水龙头拧到一半,水照样到不了目的地。这篇文章想把 TCP 拥塞控制这件事从头讲一遍:它到底在解决什么问题,BBR 和 Cubic 差在哪里,怎么在你自己的服务器上验证,以及哪些参数不该乱动。

想一边看原理一边在自己机器上抓包对比延迟和丢包的,可以配合 弱网管家(网络诊断优化工具) 这类工具做链路质量摸底,先知道底子怎么样,再谈调优才有意义。

TCP拥塞控制与BBR加速原理示意图

拥塞控制到底在管什么

先说最根本的一点:TCP 并不是「发得多就一定快」。发送方在往链路里灌数据之前,必须自己判断「这条路上现在塞不塞得下」,判断依据有两个指标时延(延迟)和丢包。

时延升高的原因通常是链路前面的某个路由器队列排长了。数据到了路由器但排队等着才能转发,这段等待时间就体现为 RTT 上升。丢包的原因则是队列满了,新到的包被丢掉。

所以拥塞控制算法的本质,是回答一个问题:我现在还能不能再多发一点?发得太少,管道空着,浪费带宽;发得太多,队列爆掉,丢包重传,反而更慢。这个平衡点就是拥塞窗口 cwnd,它决定了一次能往网络里塞多少字节。而「用多快的速度往里塞」由另一个参数控制,叫发送速率 pacing rate。

算法要做的事,就是不断观察 RTT 和丢包率这两个信号,反过来调整 cwnd 和 pacing rate。Cubic 是 Linux 2.6 之后到 4.9 时代的默认算法,BBR 是 Google 在 2016 年提出来、在 4.9 之后成为新默认的一代算法。两者的差别,就在于「怎么观察信号」和「怎么调整」这两件事上。

Cubic与BBR信号反馈机制对比图

Cubic 的思路:把时延当主要信号

Cubic 的做法接近 Reno 加 NewReno 的改良版,它的核心思想是「用时延变化判断网络是否变堵」。网络通畅的时候它大胆地加速窗口增长,一旦检测到 RTT 上升,就认为是网络开始拥堵,开始退让。而且它用了一个三次方函数来控制增长曲线,使得在同一个 RTT 区间里,窗口增长跟历史拥塞点的距离相关,从而在长肥管道(bufferbloat 严重的链路)上尽量把缓冲区填满,榨干带宽。

这套逻辑在数据中心内部的短距离高带宽链路上表现很好。但一旦链路过长、延迟本身很大、丢包又是随机发生的时候,它的两个软肋就暴露出来了:

第一,它把丢包当成拥塞的唯一铁证。可路由器队列满了才丢包,但队列满了的前提是缓冲区被填满,也就是 RTT 已经涨上去了。等丢包真的发生,网络往往已经堵了一段时间。所以 Cubic 恢复速度慢,代价直接体现在延迟上。

第二,长肥管道里缓冲区被刻意填满。为了吃满带宽,它会让队列保持在一个高位,结果就是带宽利用率上去了,RTT 也跟着飙上去了。对用户来说就是「下载速度挺快,但点个页面要等好几秒才出东西」。这是典型的 bufferbloat。

BBR 的思路:把带宽和 RTT 分开测

BBR 最大的贡献,是把「网络带宽」和「网络往返时延」当成两个独立的量分别估计,而不是像 Cubic 那样从丢包和时延抖动里间接猜。Google 的团队发现,只要能持续测出瓶颈带宽(bottleneck bandwidth)这个值,就能推算出管道里在途数据的理想总量:BDP = 带宽 × RTT。

BDP 就是这条管道里「应该同时有多少数据在飞」。发得太少,管道填不满;发得太多,多出来的部分只能进路由器队列里排队,白白增加延迟。BBR 的目标就是把在途数据量稳定在 BDP 附近,这个状态叫「带宽饱和但队列不排队」,翻译成人话就是:速度拉满,延迟不涨。

它靠三个速率模型来工作。第一个是 BtlBw(瓶颈带宽),取过去若干个发送周期里测到的最大交付速率,还会主动用「1.25 倍探测」的方式隔一段时间去挑战一下瓶颈,防止长期被误判限速。第二个是 RTprop(最小往返时延),BBR 持续跟踪一个滑动窗口内的最小 RTT,这个值代表链路「空载时」的延迟。第三个是 BtlBw × RTprop 算出来的目标在途量,BBR 会围绕这个目标去调节 cwnd 和 pacing rate。

启动阶段 BBR 会跑一个 STARTUP 阶段,类似慢启动,快速把 cwnd 拉起来探测带宽;然后进入 PROBE_BW 稳态,通过周期性升压来持续校准带宽估计;剩下的时间在 PROBE_RTT 阶段之间穿插,定期把窗口压到最小以刷新 RTprop 采样,防止链路上新增的排队把 RTprop 估计抬高。

还有个细节值得说:BBR v1 只看应用写入 socket 的速度来判断带宽,这带来了「应用写不满就测不准」的问题,所以在 RTT 稳定但应用稀疏发送的场景里表现一般。后来 Google 推出的 BBR v2 加上了 BBR2 的一些改进,Linux 4.19 之后的内核都带上了 v2,可以手动启用。

服务器上配置BBR拥塞控制的命令行操作场景

在自己服务器上换 BBR 的完整步骤

动手之前先确认内核版本,BBR 需要 4.9 以上:

uname -r

然后看内核有没有编进 BBR 模块:

sysctl net.ipv4.tcp_available_congestion_control

输出里如果没有 bbr,说明模块没编进内核,得先把它加载出来。老内核需要 modprobe tcp_bbr,然后确认 lsmod | grep bbr 有结果。新一些的发行版(CentOS 8、Debian 11、Ubuntu 20.04 之后)一般默认带上了,不用折腾。

确认可用之后,切算法并写进配置:

echo "net.ipv4.tcp_congestion_control = bbr" > /etc/sysctl.conf
sysctl -p

回读一下确认生效:

sysctl net.ipv4.tcp_congestion_control

返回 bbr 就说明切换成功。有几个参数建议一起配上:

net.core.default_qdisc = fq,这是 BBR 官方文档明确要求的配套项。fq 是 fair queueing 调度器,能让 BBR 的 pacing 机制真正生效。不设 fq 的话,BBR 的速率控制会打折,很多人换完 BBR 没效果就是因为漏了这一条。

net.ipv4.tcp_mtu_probing = 1,开启路径 MTU 探测。跨境链路经常存在 PMTU 黑洞,就是大包发出去被丢了但没人告诉你,小包却正常。不开这个探测,TCP 会在这种链路上莫名其妙地卡住,表现和拥塞控制无关,很容易误判。

net.core.default_qdisc = fq 之外,还可以考虑 net.ipv4.tcp_slow_start_after_idle = 0,避免长空闲连接恢复时又从慢启动重来。

改完注意两件事:一是 sysctl -p 只是临时生效,要写进文件才能扛住重启;二是有正在跑的长连接的话,连接建立时协商的算法已经定下来了,改完必须重启业务进程或者重连才会用上新算法。这一点是我见过最多人踩的坑改完 sysctl,测速结果纹丝不动,排查半天才发现是 curl 的连接还没断。

跨境服务器带宽与延迟指标检测工作台

怎么验证到底有没有效果

别用 ping 判断拥塞控制效果,那是最常见的误区。ping 只测 RTT,不测吞吐,而且 ping 的包很小,根本填不满管道。

我用得比较顺手的是这几种组合:

iperf3 -c 目标服务器 -P 8 -t 30 跑多流并发,这是最接近真实业务的测法,8 条流能把瓶颈带宽填满。观察两端的 Retr(重传次数)和 Cwnd(拥塞窗口)随时间的变化,重传少、cwnd 稳定说明链路健康。

ss -ti 可以直接看当前 TCP 连接的拥塞控制算法和实时 cwnd:

ss -tin dst 目标IP

输出里 cubic wscale:... 就说明这条连接还在用 Cubic,bbr wscale:... 才是切过来了。

nstat -az | grep -i retrans 看累计重传统计,重传率高说明链路本身在丢包,这时候光换算法效果有限,得先解决物理链路质量。

还有一个经验性的判断标准:换 BBR 之后,吞吐提升的同时 RTT 应该基本持平甚至下降。如果你发现吞吐上去了但 RTT 同步飙升,那多半是 qdisc 没设成 fq,或者上游还有别的瓶颈在排队。

BBR 不是万能药

写到这里得泼点冷水。BBR 解决的是「链路长、缓冲大、随机丢包」这一类问题,对应的是跨境线路、海外节点访问这类场景。它并不能:

一、把 5M 变成 50M。瓶颈带宽就是 5M,BBR 顶多帮你把 5M 用满,之前浪费的那部分能捞回来而已。

二、解决物理层面的问题。线路本身丢包率高、邻居互相干扰、机房上游抖动,这些 BBR 都救不了。

三、保证所有业务都变快。BBR 是个更激进的 pacing 策略,在多租户共享、抖动剧烈的线路上,收益可能不如预期,某些场景下甚至不如 Cubic 稳。

另外提醒一句,别把 tcp_mem、rmem、wmem 这些内存相关的参数拿来「顺手调大」。这几个值涉及的是 socket 缓冲区上限,跟拥塞控制的收益是两回事,乱调反而可能把内存吃满导致 OOM。真正值得动的就三样:拥塞控制算法、default_qdisc、tcp_mtu_probing。

我的收尾清单

每给一台新机器配完,我都会按这几条过一遍:

一、uname -r 确认内核 4.9 以上,不满足就先考虑升内核还是换机器。

二、sysctl net.ipv4.tcp_available_congestion_control 确认 bbr 在列表里。

三、写配置文件时把 net.core.default_qdisc = fq 和 net.ipv4.tcp_congestion_control = bbr 一起写上,别漏。

四、sysctl -p 之后重启业务进程或断开重连,让新连接用上新算法。

五、iperf3 打一轮前后对比,同时用 ss -tin 确认连接上标的是 bbr。

六、记录改前改后的 RTT 和重传率,写进自己的运维文档里,不然过两个月你根本想不起来这台机器动过什么。

整套逻辑捋下来其实就一句话:带宽是运营商给你的上限,拥塞控制决定你能把这条管子用到几成。长肥管道上 CUBIC 倾向于用丢包和延迟抖动换吞吐,代价是延迟被推高;BBR 通过独立估计带宽和最小 RTT,把在途数据量稳定在 BDP 附近,力求速度和延迟兼得。理解了 BDP 这个概念,剩下的就是照着上面那份清单在机器上一条条敲下去,再拿 iperf3 把前后数据一对比,结论自然就出来了。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶顶
    • 1 难过难过
    • 5 囧囧
    • 3 围观围观
    • 2 无聊无聊

    发表评论

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲