Linux sysctl 网络参数调优实战:高并发与长连接场景下的内核配置

很多服务端程序上线后表现很怪:压测时 QPS 上不去、长连接跑着跑着就大面积超时、新连接偶尔被悄悄丢掉。代码没改,机器 CPU 和内存也都没满,问题往往出在Linux 内核的默认网络参数太保守

对外业务(尤其是高并发短连接 + 海量长连接的混合场景)下,内核的半连接队列、TIME_WAIT 回收、TCP 缓冲区、拥塞控制算法都是按"通用服务器"预设的,直接拿来跑真实流量常常不够。这篇文章把生产环境里最该调的几个 sysctl 参数一次讲透,并给出一段可直接落地的配置。

一、先看清默认参数为什么不够

Linux 的默认网络栈是为"能跑通"设计的,不是为"高并发跑满"设计的。几个典型瓶颈:

  • 连接队列太小net.core.somaxconn 默认往往只有 128,高并发下新连接会在内核队列排队甚至被丢弃。
  • TIME_WAIT 堆积:短连接密集型服务,端口很快被 TIME_WAIT 占满,新连接"卡住连不上"。
  • 缓冲区偏小tcp_rmem/tcp_wmem 默认上限低,大带宽、高延迟链路上吞吐上不去。
  • 拥塞控制保守 :默认 cubic 在长肥管道(高带宽时延积)下恢复慢。

调参不是"越大越好",而是让内核参数匹配你的真实流量特征。

二、连接队列:别让新连接死在门口

复制代码
# 查看当前值
sysctl net.core.somaxconn
sysctl net.core.netdev_max_backlog
sysctl net.ipv4.tcp_max_syn_backlog

# 临时生效
sudo sysctl -w net.core.somaxconn=65535
sudo sysctl -w net.core.netdev_max_backlog=65535
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=65535

somaxconn 控制全连接队列(accept 队列)上限,注意应用层监听时的 backlog 参数也不能小于它,否则会被截断。tcp_max_syn_backlog 是半连接队列,防御 SYN 洪峰 + 高并发建连都靠它。netdev_max_backlog 是网卡收包软中断的处理队列,网卡扛量大的服务要调高。

同时别忘文件描述符上限(每个连接都要一个 fd):

复制代码
# 查看系统级 fd 上限
cat /proc/sys/fs/file-max
# 临时调高
sudo sysctl -w fs.file-max=1000000

应用自身的 ulimit -n 也要同步放开,否则内核放开了、进程还是建不了连接。

三、TIME_WAIT 与端口复用:短连接服务的命门

短连接(每次请求新建连接、用完即关)会留下大量 TIME_WAIT。默认 60 秒才回收,高 QPS 下本地端口瞬间被占满,表现为"明明对端没挂,自己却连不出去"。

复制代码
# 开启 TIME_WAIT 快速复用(仅对客户端出站连接有效)
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
# 缩短 FIN 等待
sudo sysctl -w net.ipv4.tcp_fin_timeout=30

tcp_tw_reuse=1 依赖时间戳(net.ipv4.tcp_timestamps=1,默认开),它允许在 TIME_WAIT 状态下安全地复用 socket 给新出站连接,对"自己作为客户端去连对端服务"的场景最有效。

⚠️ 注意:tcp_tw_reuse 只作用于出站,不要和当年被废弃的 tcp_tw_recycle(早已从内核移除)混淆。服务端接受入站连接时,TIME_WAIT 回收主要靠调大 tcp_max_tw_buckets 容忍堆积,而不是强行快速回收。

容忍堆积,而不是强行快速回收。

|-----------------------------|-----|-------------|---------------------|
| 参数 | 默认值 | 建议值(高并发) | 作用 |
| net.ipv4.tcp_tw_reuse | 0 | 1 | 出站连接 TIME_WAIT 安全复用 |
| net.ipv4.tcp_fin_timeout | 60 | 30 | 缩短 FIN 后等待 |
| net.ipv4.tcp_max_tw_buckets | 波动 | 可放宽到 200000 | 容忍更多 TIME_WAIT 共存 |

四、长连接保活:空闲连接别被静默掐断

长连接(推送、WebSocket、消息队列)空闲一段可能被中间设备静默掐断。内核级保活间隔默认是 7200 秒(两小时),关键业务等不起。

复制代码
sudo sysctl -w net.ipv4.tcp_keepalive_time=600
sudo sysctl -w net.ipv4.tcp_keepalive_intvl=30
sudo sysctl -w net.ipv4.tcp_keepalive_probes=5

这组值表示空闲 10 分钟开始探测、每 30 秒一次、连续 5 次无响应判定死亡。应用层最好再叠一层心跳(如每 15--30 秒 ping/pong),传输层保活兜底、应用层心跳快速感知,双保险。

另外 net.ipv4.tcp_retries2 控制丢包后重传次数,默认 15 次在弱网长连接下会导致一条死连接很久才被放弃,可适当下调到 8,让故障更快暴露:

复制代码
sudo sysctl -w net.ipv4.tcp_retries2=8

五、缓冲区与吞吐:把带宽用满

高带宽、高延迟的对外链路(长肥管道)下,TCP 窗口太小会喂不饱带宽。调大收发缓冲区:

复制代码
sudo sysctl -w net.ipv4.tcp_rmem="4096 87380 67108864"
sudo sysctl -w net.ipv4.tcp_wmem="4096 65536 67108864"
sudo sysctl -w net.ipv4.tcp_window_scaling=1

三个值分别是 min / default / max(字节)。max 调到 64MB 后配合窗口缩放,单连接在大管道上能跑出更高吞吐。内核还会根据内存压力自动在 min~max 间调节,所以给一个足够大的上限即可。

net.ipv4.tcp_mem 是系统级 TCP 内存页数上限(按页计),内存充裕的机器可放宽,避免大量连接时内核主动丢包:

复制代码
# 单位:页(通常 4KB/页),示例为 4G/6G/8G 字节换算
sudo sysctl -w net.ipv4.tcp_mem="1048576 1572864 2097152"

六、拥塞控制:长肥管道换 BBR

默认 cubic 在丢包后窗口回退激进,高带宽时延积链路上恢复慢。对"对外链路延迟大、但带宽足"的场景,换成 BBR 收益明显:

复制代码
# 确认内核已加载 bbr
ls /proc/sys/net/ipv4/tcp_congestion_control
# 查看可用算法
sysctl net.ipv4.tcp_available_congestion_control
# 临时切换
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr

BBR 基于带宽和 RTT 建模而非单纯丢包,弱网和高延迟链路上吞吐与稳定性更好。切换前确认内核支持(4.9+ 默认编译进 bbr)。

此外关闭空闲后慢启动,避免长连接空闲重传后又从很小窗口起步:

复制代码
sudo sysctl -w net.ipv4.tcp_slow_start_after_idle=0

七、写成永久配置

临时 sysctl -w 重启就丢。生产环境一律写配置文件:

复制代码
sudo tee /etc/sysctl.d/90-net-tuning.conf > /dev/null <<'EOF'
# 连接队列
net.core.somaxconn=65535
net.core.netdev_max_backlog=65535
net.ipv4.tcp_max_syn_backlog=65535
# TIME_WAIT 复用
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_max_tw_buckets=200000
# 长连接保活
net.ipv4.tcp_keepalive_time=600
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_retries2=8
# 缓冲区
net.ipv4.tcp_rmem=4096 87380 67108864
net.ipv4.tcp_wmem=4096 65536 67108864
net.ipv4.tcp_window_scaling=1
net.ipv4.tcp_mem=1048576 1572864 2097152
# 拥塞控制
net.ipv4.tcp_congestion_control=bbr
net.ipv4.tcp_slow_start_after_idle=0
fs.file-max=1000000
EOF

# 加载生效
sudo sysctl -p /etc/sysctl.d/90-net-tuning.conf

建议文件名用 90- 前缀,确保排在默认配置之后加载、不被覆盖。

八、改完怎么验证

队列是否生效:

复制代码
ss -lnt | head   # Send-Q 列应体现 somaxconn 上限
sysctl net.core.somaxconn

当前在用拥塞算法与连接状态抽样:

复制代码
sysctl net.ipv4.tcp_congestion_control
ss -i | grep -o 'bbr\|cubic' | sort | uniq -c

TIME_WAIT 数量是否收敛:

复制代码
ss -ant | awk '{print $1}' | sort | uniq -c

上线前务必在预发环境 按真实流量比例压一轮,观察 ss -ant 的状态分布、重传率(nstat -az TcpRetransSegs)和 P99 延迟,确认没有把队列调到溢出或内存吃满再推生产。

小结

sysctl 调优的本质是让内核默认假设匹配你的真实流量画像:高并发短连接重点放开队列 + 复用 TIME_WAIT;长连接重点压低保活间隔 + 快速失败;大管道重点放大缓冲区 + 切 BBR。改之前先量、改之后先压测再上线,别照抄网上"万能配置"------不同业务对连接模型和带宽时延积的敏感度差很远。把这几组参数调对,很多"莫名其妙的连接超时和吞吐上不去"会从根上消失。

相关推荐
name好难取诶11 小时前
PHP 静态分析工具实战 PHPStan 和 Psalm 完全指南
android·开发语言·php
阡陌..12 小时前
Ubuntu 22.04 离线环境完全配置指南:从 GCC 到 NVIDIA 驱动再到 Samba 共享
linux·运维·ubuntu
toooooop813 小时前
如何用 ss + ps 精准定位本机 Redis 的“隐形”消费者?
linux·数据库·redis·缓存
爱研究的小梁14 小时前
多链路聚合通信:时延控制与网络波动对抗逻辑梳理
网络·人工智能·信息与通信
重生的黑客14 小时前
Linux 进程程序替换与自定义 Shell:从 exec 函数族到命令行解释器
linux·运维·服务器·shell
北极糊的狐14 小时前
阿里云服务器-命令2-Linux 系统实时资源监视器 top 命令详解(进程级实时资源监控)
linux·运维·服务器
珠***格14 小时前
分布式光伏电站:四可装置如何实现 “可观、可测、可控、可调”
网络·人工智能·分布式·架构·能源
zbtlink15 小时前
给自动售货机配的那台WiFi6路由器,它用上了吗
网络·智能路由器
三言老师15 小时前
clear与history历史命令管理实操
linux·运维·服务器·网络·centos