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

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()参数(如 Nginx 的listen ... 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_rmem 和 tcp_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_space和cwnd是否长期小于 BDP;再用tcpprobe或 eBPF 工具抓真实窗口变化
真正卡住调优效果的,往往不是参数本身,而是没确认当前瓶颈到底在哪儿——是 SYN 队列溢出?是接收窗口卡死?还是网卡软中断不均?先 ss -i、cat /proc/net/snmp、perf record -e 'skb:*' 看两眼,比盲目改 sysctl 强得多。










