Linux TCP 拥塞控制调优实战:cubic 与 BBR 怎么选、ss 看 cwnd 重传、fq 队列与内核参数完整配置

为什么同样的服务器,别人打开快你打开慢:从拥塞控制说起

个人站长经常遇到一个说不清的问题:服务器配置不差、带宽也没跑满,但访客尤其是跨运营商、跨地区的用户,访问就是慢、就是卡顿。查 CPU 正常、查磁盘正常、查 Nginx 日志也没有 5xx,一切指标都对,就是"体验慢"。这时候,问题很可能藏在 Linux 内核的TCP 拥塞控制算法里——这是最容易被忽略、却能显著改变网络体验的一层。

本文不谈抽象的算法公式,而是从一个运维实战角度出发:讲清楚 Linux 上有哪些拥塞控制算法可选,它们分别适合什么场景,以及为什么现代服务器默认用的 cubic 在弱网环境下表现并不理想、什么时候该切换到 BBR,最后给出可验证的配置与测试流程。

拥塞控制到底在解决什么问题

TCP 在发送数据时,必须判断"网络现在能承受多快的速度"。发太快,中间路由器队列溢出会丢包,越丢越重传,形成拥塞崩溃;发太慢,带宽白白浪费。拥塞控制算法就是那个"油门调节器",负责动态找到当前网络的甜点速度。它的工作直接决定了:

  • 高延迟、有丢包链路上的实际吞吐量。
  • 带宽时延乘积大的场景(跨洲、移动网络)能否跑满。
  • 出现轻微丢包时,速度是被"拦腰砍半"还是"温和下调"。

Linux 内核从早期到现在内置了多种算法,net.ipv4.tcp_congestion_control 这个参数就是全局开关。

查看和切换:先把现状摸清楚

第一步永远是看当前在用哪个算法,别凭感觉:

sysctl net.ipv4.tcp_congestion_control
# 查看内核支持哪些算法(已加载的)
sysctl net.ipv4.tcp_available_congestion_control
# 查看当前所有连接各自用的算法,非常直观
ss -tin | grep -A1 -i cong

ss -tin 这个命令强烈推荐——它会列出每条 TCP 连接正在使用的拥塞控制算法和实时指标(cwnd 拥塞窗口、rtt 往返延迟、retrans 重传次数)。你能直接看到哪些连接在重传、哪些延迟高。

切换算法很简单,临时生效:

sysctl -w net.ipv4.tcp_congestion_control=bbr

永久生效要写进配置文件(Debian/Ubuntu 是 /etc/sysctl.d/99-tuning.conf):

net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

应用:sysctl --system。注意 BBR 官方建议搭配 fq(Fair Queue)队列调度器,否则效果打折扣。但切换前必须先确认内核里有这个模块,否则会报错:

modprobe tcp_bbr
sysctl net.ipv4.tcp_available_congestion_control | grep bbr

如果 modprobe 报"module not found",说明内核没编译进 BBR。CentOS 7 老内核、部分 OpenVZ 容器就属于这种情况,需要升级内核或换 KVM 架构的 VPS。

cubic 与 bbr 的核心差异,用人话讲

不谈公式,只讲行为差异,这决定了你该选谁:

  • CUBIC(大多数发行版默认):以丢包作为拥塞信号。一旦检测到丢包,就大幅降低发送速率。它的哲学是"丢包=网络满了"。问题在于,在无线网络、跨国链路上,丢包往往不是因为拥塞,而是因为信号抖动、线路抖动。CUBIC 分不清这两者,于是把"信号差"误判成"网络满",白白降速。
  • BBR(Google 出品):不把丢包当唯一信号,而是主动测量"瓶颈带宽"和"最小 RTT",据此估算网络实际能承载的速度。它更激进地抢占空闲带宽,同时用 fq 队列来避免把缓冲区塞爆(bufferbloat)。

结论很朴素:有丢包但带宽没满、或者你面对大量移动端/跨境访客时,BBR 通常明显更快;而在一个干净的低延迟内网或同城链路里,两者差异不大。个人站长面向的是全国各地甚至海外的真实访客,这正是 BBR 的主场。

实测对比:用数据而不是信仰做决策

切换前,先在服务器上装个压测工具,对比两种算法。最直接的方式是用 iperf3 在两台机器之间跑吞吐,但个人站长往往只有一台机。退而求其次,用真实站点做端到端测量:

# 安装工具
apt install -y iperf3 curl apache2-utils

# 对比切换前后的页面加载(多次取平均,排除缓存)
for i in 1 2 3; do
  curl -o /dev/null -s -w "TTFB:%{time_starttransfer}s Total:%{time_total}s\n" \
    "https://你的域名/?_=$RANDOM"
done

重点看 TTFB(首字节时间)和 Total。更严谨的做法是从外部多点测试,可以用 mtr 看链路丢包分布:

mtr -rwzbc 100 目标IP

mtr 会逐跳显示丢包率和延迟。如果丢包集中在最后几跳(你的服务器出口或对端接入网),那说明是接入段问题,BBR 能缓解;如果从中间某跳开始持续丢包,那是骨干网的问题,换算法也救不了——这能帮你避免"病急乱投医"。

进阶:prereq 与拥塞窗口相关参数

光切算法还不够,配套几个参数让 BBR 发挥更好:

# BBR 需要较大的收发缓冲区才能填满高 BDP 链路
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# 开启 TCP 窗口缩放,老内核默认关闭,长肥管道必须开
net.ipv4.tcp_window_scaling = 1

# 拥塞窗口上限(初始窗口),调大能加快慢启动
net.ipv4.tcp_slow_start_after_idle = 0

解释几个关键的:tcp_slow_start_after_idle=0 是很多人的盲点——默认情况下,一条连接空闲一会儿后会重新从头慢启动,导致复用连接反而变慢。关掉它,长连接(如 HTTP/2、数据库连接)能保持速度。tcp_window_scaling 必须为 1,否则在带宽时延乘积大的链路上吞吐会被窗口限制死。

用 ss 深挖:看懂 retrans、cwnd 与 rtt

切换算法前,先学会读 ss 的输出,这是判断"到底哪层慢"的关键。执行:

ss -tin state established | head -40

你会看到每条连接的详细指标,重点盯这几个字段:

  • cwnd:N:拥塞窗口,当前允许的在途未确认字节数。它涨得越快、停得越高,说明算法越能利用带宽。
  • rtt:X/Y:X 是平滑往返时间,Y 是加权平均。Y 远大于 X 说明网络抖动严重。
  • retrans:N/M:N 是本连接重传次数,M 是总发送段数。比值超过 1% 就值得警惕。
  • rcv_space / bytes_acked:接收窗口和已确认字节,观察实际吞吐。

如果同一条连接上 retrans 持续增长但 cwnd 一直上不去,就是典型的"被丢包压着不准提速",这正是 CUBIC 在弱网下的通病,也正说明切换到 BBR 会有明显收益。

不同场景该怎么选:一张决策表

拥塞控制没有万能解,要看你的访客画像:

  • 访客全国分布、有移动端、偶尔跨境:选 bbr,搭配 fq,这是最稳的现代组合。
  • 纯内网、同城低延迟链路:默认 cubic 就够,改与不改差异微乎其微。
  • 高丢包的卫星/偏远链路:可以试试 bbr,对丢包容忍度高。
  • 老内核无法加载 BBR 模块:退而求其次,考虑升级内核或更换 VPS 架构,别硬扛。

记住一个原则:面向真实互联网、有跨网跨区访客的站点,BBR 是默认该上的。纯本地测试环境才无所谓。

验证与回退:改完必须能测、能退

任何内核参数调整都要有回退方案。切换前先记下原值:

sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc

把它抄到笔记里,出问题一条命令切回去:

sysctl -w net.ipv4.tcp_congestion_control=cubic
sysctl -w net.core.default_qdisc=fq_codel

然后再从外部多点测量。可以用免费的在线测速或让你在不同城市的朋友帮忙访问,重点感受"打开页面是不是更快了、卡顿是不是少了"。更严谨的做法是部署一个前端埋点,记录真实访客的 TTFB 分布,对比切换前后一周的数据。运维决策的底气,永远来自可观测的数据,而不是一篇文章说 BBR 更快。

五个必须注意的坑

  1. OpenVZ 容器用不了 BBR:容器共享宿主内核,你无法加载模块。先 cat /proc/sys/net/ipv4/tcp_available_congestion_control 确认,没有 bbr 就是架构不支持,只能换 KVM VPS。
  2. 忘了配 qdisc=fq:只切 bbr 不配 fq,在高负载时可能仍有缓冲膨胀,效果打折。两个一起配。
  3. 盲目追求"越新越好":BBRv1 和 BBRv2/v3 行为差异很大,某些内核版本里 BBr2 在低带宽下反而不如 v1。切换后一定要实测,别只看版本号。
  4. 调整 rmem/wmem 过大反而伤内存:每个连接最多吃 16M 缓冲,高并发时内存消耗惊人。1G 内存的小机器别把 max 设太大,先看 free -h 和连接数。
  5. 改完不验证:一定要 sysctl -w 后用 ss -tin 确认新连接真的用上了新算法,旧连接不会自动切换。

总结:网络体验优化的性价比之王

拥塞控制是少数"改几行配置、不花钱、却能让全国访客明显感觉变快"的优化项。对个人站长来说,行动路径很清晰:先 ss -tin 摸清现状和重传情况,用 mtr 判断丢包位置,确认内核支持 BBR 后切换到 bbr + fq 并配好缓冲区参数,最后用多点实测验证收益。切记,网络优化没有银弹,数据永远比信仰可靠——测了再改,改完再测,这才是运维该有的态度。

Last modification:October 3rd, 2026 at 01:25 pm

Leave a Comment