Linux TCP/IP 参数调优实战

2次阅读

linux tcp性能调优需针对性处理:关闭tcp_slow_start_after_idle避免空闲连接降速;调大somaxconn并同步应用backlog防syn队列溢出;tcp_tw_reuse仅对客户端有效且需timestamps支持;rmem/wmem按bdp合理设置;调优前务必用ss、perf等工具定位真实瓶颈。

Linux TCP/IP 参数调优实战

tcp_slow_start_after_idle 导致连接突然变慢

Linux 默认开启 tcp_slow_start_after_idle,空闲连接重传时强制回到慢启动阶段——哪怕之前已跑满带宽。这不是 bug,是 RFC 要求的“保守行为”,但对长连接、rpc数据库连接池这类场景就是性能杀手。

实操建议:

  • 确认当前值:sysctl net.ipv4.tcp_slow_start_after_idle(默认为 1)
  • 关闭它:sysctl -w net.ipv4.tcp_slow_start_after_idle=0,并写入 /etc/sysctl.conf
  • 注意:仅影响空闲后恢复的连接,不影响新连接或持续传输流
  • 云环境需留意:某些厂商(如 AWS EC2)内核可能 patch 过该行为,实测前先 ss -i 看重传时 cwnd 是否被重置

net.core.somaxconn 和应用 listen() 的 backlog 不匹配

应用调用 listen(fd, backlog) 传的 backlog 值,会被内核截断为 min(backlog, net.core.somaxconn)。很多 Go/Python 服务默认用 128,而系统默认 net.core.somaxconn 是 128 或更低,结果 SYN 队列实际容量卡死,高并发下出现“connection refused”或延迟飙升。

实操建议:

  • 查当前限制:sysctl net.core.somaxconn,同时用 ss -lnt 观察 Recv-Q 是否长期打满
  • 调大它:sysctl -w net.core.somaxconn=65535,并同步改应用代码里的 listen() 参数(如 nginxlisten ... backlog=65535
  • 注意:net.core.somaxconn 影响所有 socket;但 net.core.netdev_max_backlog 控制的是软中断收包队列,别混淆
  • docker 容器里要显式传递 sysctl 参数,否则继承 host 但可能被 Namespace 隔离限制

tcp_tw_reuse 在 TIME_WAIT 多时真能用?

tcp_tw_reuse 允许内核复用处于 TIME_WAIT 状态的四元组,前提是新连接的时间戳严格大于前一个连接的 FIN 时间戳。它不是万能开关——只对**客户端主动发起连接**(比如 http client、mysql client)有效,对服务端监听端口完全无效。

实操建议:

  • 启用前先看现状:netstat -ant | grep TIME_WAIT | wc -l,再结合 ss -s 看 total-sockets 和 time-wait 数量级
  • 仅在明确是客户端连接爆发(如爬虫、微服务间大量短连)时开:sysctl -w net.ipv4.tcp_tw_reuse=1
  • 必须配合 net.ipv4.tcp_timestamps=1(默认通常已开),否则不生效
  • 别碰 tcp_fin_timeout 或直接 net.ipv4.tcp_tw_recycle(后者在 NAT 环境下会丢包,已从 4.12+ 内核移除)

net.ipv4.tcp_rmem / tcp_wmem 的三个值怎么设才不翻车

tcp_rmemtcp_wmem 各有三项:min default max。很多人直接抄 “4096 65536 67108864”,结果小包延迟升高、大文件吞吐上不去,甚至触发 TCP SACK 丢包重传。

实操建议:

  • 先算理论 BDP(Bandwidth-Delay Product):带宽(Bps)× RTT(秒)。例如 10Gbps + 1ms RTT → BDP ≈ 1.25MB。max 至少设为 BDP 的 2 倍
  • default 值影响新建连接初始窗口,不宜过小(65536 是底线),也不宜过大(导致首包重传放大)
  • min 值极少起作用,保持 4096 即可;但若用 RPS/RFS,min 过小可能加剧 cache line bounce
  • 动态调整优先于静态拍脑袋:用 ss -i 观察 rcv_spacecwnd 是否长期小于 BDP;再用 tcpprobe 或 eBPF 工具抓真实窗口变化

真正卡住调优效果的,往往不是参数本身,而是没确认当前瓶颈到底在哪儿——是 SYN 队列溢出?是接收窗口卡死?还是网卡软中断不均?先 ss -icat /proc/net/snmpperf record -e 'skb:*' 看两眼,比盲目改 sysctl 强得多。

text=ZqhQzanResources