Linux TCP 调优实战:从 BDP、拥塞控制到内核参数

一篇以测量为起点的 Linux TCP 调优指南,涵盖 BDP、套接字缓冲区、CUBIC/BBR、fq、连接队列、MTU 黑洞、验证与回滚。

Linux TCP 调优最容易掉进两个坑:一是从网上复制一整套“万能参数”,二是只看测速峰值,不看重传、延迟和内存。真正有效的调优应当从链路的带宽、往返时延(RTT)、丢包率和业务并发模型出发,先测量,再修改,最后用同样的方法复测。

一、先理解调优目标:吞吐、延迟与稳定性

TCP 性能不是单一指标。大文件传输通常关注吞吐量;网页、API 和游戏更关心 RTT、抖动与排队延迟;高并发网关还要关注连接队列、端口和内存。提高缓冲区上限可能改善长肥网络上的吞吐,却也可能增加内存占用,甚至放大排队延迟。因此,参数必须服务于明确的瓶颈。

二、建立基线:不要在没有数据时改 sysctl

调优前至少记录内核版本、拥塞控制算法、队列规则、网卡统计和 TCP 连接状态:

uname -r
sysctl net.ipv4.tcp_congestion_control
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.core.default_qdisc
ip -s link
nstat -az | egrep 'TcpRetransSegs|TcpExtTCPLostRetransmit|TcpExtTCPTimeouts'
ss -s
ss -tinm

ss -tinm尤其有用:它能显示连接使用的拥塞控制算法、RTT、拥塞窗口(cwnd)、重传、pacing rate 以及套接字内存。测试吞吐时可使用 iperf3,但应同时记录空载 RTT、负载下 RTT 和重传数量。只看“跑满带宽”可能掩盖严重的 Bufferbloat。

三、用 BDP 判断缓冲区是否可能成为瓶颈

带宽时延积(Bandwidth-Delay Product,BDP)表示一条链路在一个 RTT 内可容纳的在途数据量:

BDP(字节)= 带宽(bit/s)× RTT(秒)÷ 8

例如,1 Gbit/s、RTT 100 ms 的链路,BDP 约为 12.5 MB(11.92 MiB)。如果发送窗口或接收窗口长期明显低于这个量级,单连接就可能难以跑满链路。

Linux 默认启用 TCP 接收缓冲区自动调节。tcp_rmemtcp_wmem 的三个值分别是最小值、默认值和最大值;net.core.rmem_max/wmem_max 则限制应用通过套接字选项申请的上限。不要把所有值都无脑设置成几百 MB:高并发时,每个连接的内存会叠加。

sysctl net.ipv4.tcp_rmem
sysctl net.ipv4.tcp_wmem
sysctl net.core.rmem_max
sysctl net.core.wmem_max
sysctl net.ipv4.tcp_moderate_rcvbuf

四、拥塞控制:CUBIC 与 BBR 怎么选

CUBIC是成熟的丢包型拥塞控制算法,兼容性好,常见 Linux 发行版默认使用它。BBR根据带宽和 RTT 模型控制发送速率,在高 RTT、存在随机丢包或跨运营商链路上经常更有优势,但它不是“开启就必然变快”,效果仍取决于瓶颈位置、队列、内核版本和对端行为。

先确认内核是否提供 BBR:

modprobe tcp_bbr
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
lsmod | grep tcp_bbr

如果可用,可进行一组可回滚的 A/B 测试:

# 临时切换;重启后通常恢复
sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr

# 回退示例
sysctl -w net.ipv4.tcp_congestion_control=cubic

fq提供流量整形与 pacing 支持,常与 BBR 配合。切换后应重新比较吞吐、P95/P99 RTT、重传率和 CPU 使用率,而不是只跑一次测速。

五、队列与高并发服务器

当应用接受连接的速度跟不上突发流量时,需要同时检查应用监听队列和内核上限:

sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
ss -lnt
nstat -az | egrep 'ListenOverflows|ListenDrops|TCPReqQFullDrop'

如果 ListenOverflowsListenDrops 持续增长,先确认应用的 worker 数量、事件循环、数据库和上游依赖是否已经饱和。单纯调大 somaxconn 只能吸收短暂突发,不能修复处理能力不足。

六、MTU 黑洞与异常卡顿

VPN、隧道、PPPoE 或错误过滤 ICMP 的网络可能出现 PMTU 黑洞:连接可以建立,但传输较大数据时卡住。应先用 tracepath、抓包和不同大小的探测包确认问题。必要时可让 TCP 在发现黑洞时启用 MTU 探测:

# 0:关闭;1:检测到 ICMP 黑洞时启用;2:始终启用
sysctl -w net.ipv4.tcp_mtu_probing=1

相比直接全局降低网卡 MTU,模式 1 通常更保守,但仍应通过真实故障链路验证。

七、一份保守的测试模板

下面不是“万能配置”,而是一份适合现代 Linux、需要测试后再持久化的起点。缓冲区上限应按 BDP、并发连接数和内存预算调整:

# /etc/sysctl.d/90-tcp-tuning.conf
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# 为高 BDP 链路提供合理上限;不要盲目继续放大
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 131072 16777216
net.ipv4.tcp_wmem = 4096 16384 16777216

# 仅在确认存在 PMTU 黑洞风险时使用
net.ipv4.tcp_mtu_probing = 1

应用前先备份当前值;用 sysctl --system 加载后检查是否有“不存在的键”或模块不可用错误。远程服务器应保留 SSH 回退通道,不要在一次变更中同时修改防火墙、路由和 TCP 参数。

八、验证与回滚

  • 在相同时间段、相同测试端点下做修改前后对比;
  • 至少进行多轮测试,记录中位数及 P95/P99,而非最佳值;
  • 同时观察吞吐、RTT、重传、丢包、CPU 和内存;
  • 检查业务日志和连接错误,不只看 iperf3
  • 效果不明确或尾延迟恶化时,删除配置文件并恢复原值。

最终原则很简单:先定位瓶颈,再做最小修改;每次只改变一组变量,并保留可复现的前后数据。TCP 调优的价值不在于参数数量,而在于能否让特定业务在真实网络下更快、更稳,同时不牺牲尾延迟和系统可控性。

参考资料