前言
压测时出现 Too many open files、大量 TIME_WAIT、连接队列溢出——这些都不是应用 bug,是内核默认参数太保守。生产服务器上线清单里,sysctl 调优应有一席之地。
一、sysctl 机制
# 查看
sysctl net.ipv4.tcp_tw_reuse # 单个参数
sysctl -a | grep somaxconn # 搜索
# 临时生效(重启丢失, 调试用)
sysctl -w net.core.somaxconn=4096
# 永久生效: 写入 /etc/sysctl.d/*.conf
echo "net.core.somaxconn = 4096" > /etc/sysctl.d/99-tuning.conf
sysctl --system # 重载全部配置
调整前先看现状:
ulimit -n # 当前 shell 的 fd 上限
cat /proc/sys/fs/file-nr # 已分配/未用/最大 fd
ss -s # 连接概览
netstat -s | grep -iE "overflow|drop" # 队列溢出统计(调优依据!)
二、必调参数详解
1. 文件描述符(万物的前提)
# /etc/sysctl.d/99-tuning.conf
fs.file-max = 1048576 # 全系统 fd 上限
# 还要改用户级限制(systemd 服务走另一条路!)
cat >> /etc/security/limits.conf <<'EOF'
* soft nofile 65535
* hard nofile 65535
EOF
# systemd 管理的服务: 在 unit 里加
[Service]
LimitNOFILE=65535
常见坑:改了 limits.conf,systemd 服务没生效——
cat /proc/<pid>/limits验证实际值。
2. TCP 连接复用与 TIME_WAIT
net.ipv4.tcp_tw_reuse = 1 # 允许复用 TIME_WAIT 端口用于出站连接(客户端侧)
net.ipv4.tcp_fin_timeout = 30 # FIN_WAIT2 超时(默认60s)
net.ipv4.ip_local_port_range = 10240 65000 # 出站端口范围(短连接多时扩大)
TIME_WAIT 认知纠偏:
- TIME_WAIT 是主动关闭方的正常状态(2MSL,约60s),是 TCP 可靠性的保障
- 几万个 TIME_WAIT 本身不是故障;先治连接方式再调参数:
- 短连接风暴 → 改长连接/连接池(应用层根治)
- 出站端口耗尽 →
tcp_tw_reuse=1+ 扩ip_local_port_range - 服务器被动TIME_WAIT堆积 → 检查是否应用频繁主动断连
3. 监听与 accept 队列
net.core.somaxconn = 4096 # 全局监听队列上限(nginx listen backlog 不能超过它)
net.ipv4.tcp_max_syn_backlog = 8192 # 半连接队列(SYN 待完成握手数)
net.core.netdev_max_backlog = 16384 # 网卡收包队列
队列溢出的证据:
netstat -s | grep -i "listen"
# XXX times the listen queue of a socket overflowed ← 就是它!
4. TCP 缓冲区(大流量传输)
net.core.rmem_max = 16777216 # 套接字读缓冲上限
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216 # 最小/默认/最大(自适应)
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_mtu_probing = 1 # MTU 黑洞探测(云上跨网传输卡住时救急)
5. TCP 保活与快速失败
net.ipv4.tcp_keepalive_time = 600 # 空闲600s后开始探测(默认7200太久)
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3 # 3次失败即断(90s发现死连接)
net.ipv4.tcp_syn_retries = 3 # 出站SYN重试(默认6次≈2分钟才报错)
6. 内存与 SWAP
vm.swappiness = 10 # 尽量少用swap(数据库/延迟敏感服务设1-10)
vm.overcommit_memory = 1 # Redis等场景需要(按需)
vm.max_map_count = 262144 # ES等大量mmap的程序需要
7. 安全相关(顺手加固)
net.ipv4.conf.all.rp_filter = 1 # 反向路径校验(防源地址欺骗)
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.tcp_syncookies = 1 # SYN Flood 防护(一般默认开)
三、落地模板
/etc/sysctl.d/99-tuning.conf(通用 Web/中间件服务器):
# ---- fs ----
fs.file-max = 1048576
# ---- core ----
net.core.somaxconn = 4096
net.core.netdev_max_backlog = 16384
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# ---- ipv4 tcp ----
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.ip_local_port_range = 10240 65000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_mtu_probing = 1
# ---- vm ----
vm.swappiness = 10
sysctl --system # 应用并检查有无报错
sysctl net.core.somaxconn # 验证
四、验证调优效果
# 1. 压测前后对比队列溢出计数
netstat -s | grep -i overflow
# 2. fd 使用量趋势
watch -n1 cat /proc/sys/fs/file-nr
# 3. TIME_WAIT 变化
ss -tan state time-wait | wc -l
# 4. 实测: ab/wrk 压 QPS
wrk -t4 -c1000 -d30s http://target/
五、调优原则(比参数本身重要)
- 有依据再调:
netstat -s的溢出/丢弃计数、ss -s的连接分布——先诊断后开药 - 一次改一组:改完记录基准,可对比回滚
- 应用层优先:连接池、长连接、异步化能解决的,不推给内核
- 别抄"万能优化脚本":
tcp_tw_recycle(已在 4.12 内核移除,开了反而 NAT 环境丢连接)就是血案
小结
| 症状 | 药方 |
|---|---|
| Too many open files | fs.file-max + limits + systemd LimitNOFILE |
| listen queue overflow | somaxconn + 应用 backlog |
| 出站端口耗尽 | tcp_tw_reuse + ip_local_port_range |
| 大文件传输慢 | tcp_rmem/wmem |
| 死连接挂半小时 | keepalive 三件套 |
| 内存吃紧狂 swap | vm.swappiness |
本文是「Linux 运维」系列第 11 篇。