同一条 100 Mbps 的线路,两台服务器下载同一个文件,速度可能差出几倍。差别常常不在带宽,而在发送方如何判断此刻能发多快,这就是 TCP拥塞控制。本文拆开 CUBIC 与 BBR 两套算法,给出切换、观测与排错的步骤,也说清哪些情况下换了没用。
TCP 拥塞控制要解决什么:窗口与在途数据
TCP 发送方维护一个拥塞窗口 cwnd,表示已发出但尚未确认的数据上限。窗口内的数据在网络里排队,接收方每回一个 ACK,窗口才有机会变大。
RFC 5681 定义的 Reno 是加性增、乘性减:拥塞避免阶段每个 RTT 大约加一个 MSS,遇到丢包把窗口砍半。规则简单,但在高带宽长延迟链路上,窗口从砍半恢复到原大小要花很多个 RTT。
在拥塞避免之前还有一段慢启动:窗口按 ACK 指数增长,直到碰到慢启动阈值或检测到丢包才切换模式。这段的长度,决定了短连接能不能在结束前跑到链路容量。
链路容量可以用带宽时延积估算。100 Mbps 乘 100 ms 往返,大约需要 1.25 MB 的在途数据才能喂满。窗口涨得太慢,链路就闲着。反过来,中间设备的缓冲区如果太深,队列排满会把 RTT 从 20 ms 推到 200 ms,此时窗口再大也只是把数据堆在队列里。
CUBIC 的账本:三次函数与 0.7 的退让
CUBIC 不以窗口的当前值为基准,而是和上次拥塞前的窗口 W_max 做比较,用三次函数决定增速:W_cubic(t) = C × (t − K)³ + W_max。K 是从当前窗口长回 W_max 所需的时间,等于 (W_max − cwnd_epoch) 除以 C 后开三次方。
RFC 9438 规定 C 取 0.4,乘法减少因子 beta 取 0.7;作为对照,Reno 的 beta 是 0.5。丢包后只退 30%,恢复更快,代价是收敛慢一些。
增长曲线与 RTT 解耦,不同 RTT 的流在稳态下窗口接近,吞吐比按 RTT 反比线性变化。这让它在跨洲链路上比 Reno 更能吃满带宽。
三次曲线在 W_max 附近趋于平缓,超过 W_max 后又加速上探,形成凹区与凸区两段。配合快速收敛,新流加入时老流会主动下调 W_max,把带宽让出来。
但它仍然把丢包当成拥塞信号。链路存在随机丢包时(无线接入、跨境线路),窗口会被反复压下去,这是 CUBIC 在弱网环境里吃力的根源。慢启动阶段 RFC 9438 建议用 HyStart++ 提前退出,避免一上来就冲过头。
RFC 9438 同时说明,CUBIC 已是 Linux、Windows 与 Apple 系统栈的默认算法,QUIC 与 SCTP 也能直接采用。
BBR 的账本:不靠丢包,靠带宽与最小 RTT
BBR 换了一套信号。它持续估计两个量:瓶颈带宽 BtlBw 与最小往返传播时间 RTprop,再把在途数据控制在两者乘积附近,并按估计带宽匀速发包,也就是 pacing,而不是等丢包才刹车。
draft-ietf-ccwg-bbr 在 2026 年 11 月 2 日的第 07 版里规定的是 BBRv3,目标状态是 Experimental。摘要给出的两点收益很具体:浅缓冲或随机丢包的瓶颈上吞吐更高,深缓冲的瓶颈上排队时延更低。
它同时管两件事:cwnd 决定能放多少数据在途,pacing_rate 决定这些数据以多快的节奏发出。两者都跟着模型走,所以窗口曲线比 CUBIC 平顺,短 RTT 链路上两者的差距也会小很多。
代价同样明确。为了重测最小 RTT,BBR 会周期性进入 ProbeRTT,把在途数据压低一阵,草案估算这部分损失不超过 1% 带宽。路径突变之后,最小值过滤器更新也需要时间。
大文件同步这类长连接对窗口变化很敏感,站内Syncthing 的同步实践里,吞吐波动往往就来自这里。
在 Linux 上切换与观测:三条命令

先看当前值:sysctl net.ipv4.tcp_congestion_control;再看可用列表:sysctl net.ipv4.tcp_available_congestion_control。
切换要写进 /etc/sysctl.d/99-tcp.conf,两行就够:net.core.default_qdisc = fq 与 net.ipv4.tcp_congestion_control = bbr,然后执行 sysctl --system。只用 sysctl -w 改运行时,重启就还原。改动只对新建连接生效,正在传输的 SSH 或下载不会自动切换,验证时重新开一条即可。
验证券别看 sysctl。用 ss -ti 看单条连接:cwnd 是否稳定、rtt 是否被队列撑大、重传是否在涨;BBR 连接还会多出 bw、mrtt、pacing_rate 这类估算字段。
对照测试用 iperf3 分别跑 -C cubic 与 -C bbr,各测 20 秒,再用 tc netem loss 1% 模拟丢包复测。同一台机器、同一时段、同一方向,结论才有意义。典型对照是跨境 VPS 上的下载:CUBIC 在 1% 随机丢包下会明显掉速,BBR 受丢包的影响小;换到局域网内测,两者差距会缩到测量误差级别。
内核文档提醒了两点:reno 始终可用,其他算法取决于内核配置;被动连接的拥塞控制继承自监听套接字。所以反向代理、容器端口映射这类场景,要改的是监听那一侧。
什么时候别切:六个场景
- 发送方不是这台机器。拥塞控制只在发包侧生效,改下载服务器的参数不会加快你本地的上传;反过来,从 CDN 下载的速度由边缘节点决定,你能调的只有自己这一端的上传。
- 瓶颈不在网络。磁盘 IO、TLS 握手、DNS 解析、应用层串行处理,换算法都不会有改善。
- 局域网或短连接。BDP 小、连接几秒就结束,两者的差距被握手与慢启动吃掉。
- 链路里套了隧道。WireGuard 这类 UDP 隧道本身不套 TCP,但隧道里跑的若是 TCP,内外两层拥塞控制会互相影响,要两端分别测。
- 共享出口。单机切换只改变这一台的行为,公司出口或多租户环境还要看整体队列与公平性。
- 移动网络与卫星链路。RTT 波动大、随机丢包多,模型估计容易被带偏,两种算法都会掉速,只能实测。
常见误区与排错顺序
- 把 bbr 当成 BBRv3。主线内核里的 bbr 长期是 v1,v3 仍在草案与厂商分支里,sysctl 的值看不出区别,得看内核来源,这份内核与隧道调优的整理也强调了同一点。
- 以为设了 fq 才算开启。fq 是把 pacing 做细的队列,不是算法本身,关键仍是拥塞控制项。
- 忽略被动连接继承。监听套接字的算法会传给子连接,改错位置等于没改。
- 只看吞吐不看时延。BBR 可能把队列压短,也可能让同链路上的其他流更难抢,两个指标要一起看。
- 把 BBR 当通用加速开关。它优化的是拥塞判断,不改变物理带宽,也绕不开运营商侧的限速。
排错按顺序来:确认发送端,看 sysctl 当前值与可用列表,用 ss -ti 看 cwnd、rtt 与重传,再用 iperf3 做对照,最后才动队列和缓冲区参数。多数"开了 BBR 没变快"的案例,卡在前两步。改动要记下时间点与参数,出问题时才能对比回滚;生产环境先拿一台机器跑一周,再决定是否铺开。
适合自己动手的人:维护 VPS、NAS 或跨地域同步,愿意花半小时做对照测试。只想着网页快一点的话,先看 CDN、TLS 与图片体积,收益通常更直接。
相关地址
以下为文中项目的官方入口,版本号、文档与下载以这些页面为准。
- RFC 9438(CUBIC)(IETF 原文):https://www.rfc-editor.org/rfc/rfc9438.html
- BBR 拥塞控制(IETF 草案与进展):https://datatracker.ietf.org/doc/draft-ietf-ccwg-bbr/
- Linux 内核(ip-sysctl 官方文档):https://www.kernel.org/doc/html/latest/networking/ip-sysctl.html
© 版权声明
文章版权归作者所有,转载需注明出处。未声明原创的皆为网络收集,如有侵权请邮箱lishiwenhuagx@sina.com联系下架处理。




