高并发下tcp性能瓶颈通常不在应用层,而在内核参数默认值过于保守——net.core.somaxconn、net.ipv4.tcp_tw_reuse、net.ipv4.tcp_rmem这三个参数不调,其他都白搭。

直接说结论:高并发下 TCP 性能瓶颈通常不在应用层,而在内核参数默认值过于保守——net.core.somaxconn、net.ipv4.tcp_tw_reuse、net.ipv4.tcp_rmem 这三个参数不调,其他都白搭。
为什么 somaxconn 和 tcp_max_syn_backlog 必须一起调
应用 listen() 时传的 backlog 参数(比如 Nginx 的 listen ... backlog=65535)不会被完全尊重。内核实际用的是二者中的较小值:min(backlog, net.core.somaxconn);而半连接队列长度又受 net.ipv4.tcp_max_syn_backlog 限制。三者不匹配就会丢 SYN 包,现象是客户端偶发连接超时或 Connection refused。
-
net.core.somaxconn必须 ≥ 应用设置的 backlog,建议统一设为65535 -
net.ipv4.tcp_max_syn_backlog建议同步设为65535或更高(如262144),尤其在有 SYN Flood 风险时 - 改完后必须重启对应服务(如 Nginx、Redis),否则新参数对已运行进程无效
tcp_tw_reuse 开启前必须确认 tcp_timestamps 已启用
net.ipv4.tcp_tw_reuse = 1 看似能快速复用 TIME_WAIT 端口,但它的安全前提被很多人忽略:必须同时开启 net.ipv4.tcp_timestamps = 1。否则内核会静默忽略该设置,ss -s 里仍看到大量 TIME_WAIT 占满端口,最终触发 Cannot assign requested address 错误。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 检查是否生效:
sysctl net.ipv4.tcp_timestamps net.ipv4.tcp_tw_reuse,两个都得是1 - 不要碰
tcp_tw_recycle—— 它在 NAT 环境下会导致连接失败,内核 4.12+ 已彻底移除 - 如果服务是纯内网且无 NAT,
tcp_fin_timeout = 30可进一步加速回收,但别低于15
缓冲区三元组 tcp_rmem/tcp_wmem 的 max 值必须 ≤ rmem_max/wmem_max
很多人照抄网上配置写 net.ipv4.tcp_rmem = "4096 524288 16777216",却发现应用层 setsockopt(SO_RCVBUF) 失败,或 ss -i 显示接收窗口始终卡在 256KB。根本原因是没同步调大全局上限:net.core.rmem_max 默认只有 212992 字节(约 208KB),小于你设的 16MB,内核自动截断。
- 先设上限:
net.core.rmem_max = 16777216、net.core.wmem_max = 16777216 - 再设三元组:
net.ipv4.tcp_rmem = "4096 524288 16777216"(注意空格分隔,不能用逗号) - max 值按带宽 × RTT 估算:10Gbps × 10ms ≈ 12.5MB,向上取整到 16MB 是稳妥值
BBR 拥塞控制不是万能药,要关掉 tcp_slow_start_after_idle
启用 BBR(net.ipv4.tcp_congestion_control = bbr)对跨机房、高延迟链路效果明显,但默认行为有个坑:tcp_slow_start_after_idle = 1 会让空闲几秒后的长连接重新进入慢启动,吞吐瞬间腰斩。微服务间持续调用时,这比丢包还伤性能。
- 务必加一行:
net.ipv4.tcp_slow_start_after_idle = 0 - BBRv2(内核 ≥ 5.18)更激进,若线上稳定性存疑,先用 BBRv1 + 关闭 idle slow start
- 验证是否生效:
ss -i查看某连接的cwnd是否在空闲后维持高位
最易被忽略的点:所有 sysctl 修改只是运行时生效,重启就丢;/etc/sysctl.conf 里漏写 net.core.rmem_max 这类“配角参数”,主参数再优也白搭。调参不是填数字,是理清依赖链——somaxconn 控 accept 队列,tcp_tw_reuse 依赖 tcp_timestamps,缓冲区 max 值受全局上限钳制。少一环,就卡在那一环。










