默认内核参数成了性能瓶颈
当业务流量飙升到每秒数万个连接、数十万数据包时,Linux的默认sysctl配置会最先暴露出短板。文件句柄耗尽、TIME_WAIT堆积、TCP缓冲区不足、OOM……这些问题一出现,即使CPU和内存仍有富余,整个服务也会瞬间雪崩。与其盲目堆硬件,不如先把手头的内核参数调到位。
这篇文章直接围绕网络层(net.core、net.ipv4)、内存管理(vm)、文件系统(fs)、进程调度(kernel)四个维度展开。每个参数都会告诉你:为什么调、调到多少、怎么验证、如何回滚。
网络层调优:扛住百万并发连接
net.core.somaxconn & net.ipv4.tcp_max_syn_backlog
这两个参数控制TCP连接请求队列的深度。默认somaxconn=128,在高并发下,新连接直接丢包,客户端收到Connection refused。Nginx、Redis等产品自身也有backlog设置,但最终上限由这个内核参数决定。
net.core.somaxconn = 65536
net.ipv4.tcp_max_syn_backlog = 65536
为什么是65536?这个值是经验上限,再大不会提升性能反而浪费内存。尤其是SYN backlog,每个半连接占用约256字节,65536大约占用16MB,完全可接受。
net.ipv4.tcp_tw_reuse & tcp_tw_recycle(慎用)
TIME_WAIT状态在高并发短连接场景下数量惊人。解决办法:
- tcp_tw_reuse:允许客户端重用处于TIME_WAIT的socket用于新连接。对服务器端无效。可安全开启。
- tcp_tw_recycle:对NAT环境有严重副作用(可能丢弃来自NAT后的请求)。内核已不建议使用,Linux 4.12+已移除。不要设置。
net.ipv4.tcp_tw_reuse = 1
# 不要设置 tcp_tw_recycle
更稳妥的做法是开启tcp_timestamps并用tcp_tw_reuse。如果延迟敏感业务,可考虑调整tcp_fin_timeout缩减TIME_WAIT存活时间(默认60秒,可改为30秒或15秒)。
net.ipv4.tcp_fin_timeout = 15
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
解释:三个值分别表示最小值、默认值、最大值。TCP根据BDP自动调整。最小值设为4KB保证基本通信,默认值保持适中,最大值16MB保证突发大包吞吐。同时开启TCP窗口缩放:
net.ipv4.tcp_window_scaling = 1
net.core.netdev_max_backlog & 网卡队列
网卡中断到来时,数据包先进入内核的backlog队列。默认为1000,高并发下极易丢包。建议翻倍:
net.core.netdev_max_backlog = 65536
同时检查网卡多队列(RSS/RPS)是否开启,这是CPU层面的调优,不在sysctl但很关键。
内存管理调优:避免OOM与页抖动
vm.swappiness
默认60意味着内核在内存还有剩余时就开始换页。对于高并发服务,任何磁盘IO都是灾难。建议降低到10甚至0:
vm.swappiness = 10
注意:如果应用程序本身有内存泄漏风险,swappiness过低会导致OOM无法提前释放。需要结合监控平衡。
vm.vfs_cache_pressure & vm.dirty_ratio
文件系统缓存(dentry、inode)回收速度由vfs_cache_pressure控制,默认100。高并发下频繁文件操作,调大回收力度:
vm.vfs_cache_pressure = 200
脏页比率:dirty_ratio默认20%(占用内存百分比),高IO写场景下调小可防止写突发卡顿:
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.max_map_count
每个进程能拥有的内存映射区域数量。Elasticsearch、Java等进程在内存中频繁mmap,默认65530太低。建议:
vm.max_map_count = 262144
文件系统与进程调度
fs.file-max & fs.nr_open
最大文件句柄数。高并发意味着大量socket(也是文件),必须提高:
fs.file-max = 2097152
# 同时设置系统级限制
fs.nr_open = 2097152
别忘了同时修改/etc/security/limits.conf中的软硬限制,否则即使内核允许,进程仍会受到ulimit限制。
kernel.sem & kernel.msgmax
信号量和消息队列在高并发分布式日志、中间件场景下需要调整:
kernel.sem = 250 32000 100 1024
kernel.msgmax = 65536
kernel.msgmnb = 65536
kernel.pid_max
默认32768,如果进程数(包括线程)接近此值,新进程无法创建。建议设为最大:
kernel.pid_max = 4194304
实战步骤:配置、验证与回滚
第一步:备份当前配置
cp /etc/sysctl.conf /etc/sysctl.conf.bak.$(date +%Y%m%d)
第二步:写入新配置
将上述参数按需写入/etc/sysctl.conf。只写你真正需要的,别一股脑全复制。例如:
# 网络层
net.core.somaxconn = 65536
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
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_window_scaling = 1
net.core.netdev_max_backlog = 65536
# 内存
vm.swappiness = 10
vm.vfs_cache_pressure = 200
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.max_map_count = 262144
# 文件与进程
fs.file-max = 2097152
fs.nr_open = 2097152
kernel.pid_max = 4194304
第三步:生效并验证
sysctl -p
检查是否有错误(比如参数名拼写、值超出范围)。逐一确认新值已写入:
sysctl net.core.somaxconn
# 输出应为 65536
生产环境建议分批次应用,每次重启一个服务测试,观察监控指标:连接数、TIME_WAIT、内存使用、swap IO、错误日志。
第四步:回滚方案
如果调优后出现异常(比如TCP连接失败增多、OOM),立即复原:
cp /etc/sysctl.conf.bak.$(date +%Y%m%d) /etc/sysctl.conf
sysctl -p
对于单参数临时回滚,可以直接用sysctl -w var=old_value,但重启后会恢复,需一并修改配置文件。
调优不是万能药
内核参数调优只能释放操作系统层面的瓶颈。真正的极限高并发还需要应用层无阻塞IO、合理的线程模型、数据库连接池以及网络架构(如LVS、DPDK)配合。每改一个参数,必须在压测环境下做对比测试,观察CPU软中断、上下文切换、drop计数等指标。
以上配置基于Linux 4.x/5.x内核,更低版本参数可能不同(例如tcp_tw_recycle)。始终以当前内核文档为准。
延伸阅读
