Linux sysctl 内核参数调优:Web 服务器与数据库生产配置
系统讲解 Linux sysctl 内核参数的分类与调优方法,提供 Web 服务器(高并发)和数据库服务器的生产级参数配置,覆盖网络栈优化、内存管理、文件句柄、TCP 调优等核心参数,含完整的 sysctl.conf 配置模板。
Linux 默认内核参数为“通用场景”设计,不适合高并发 Web 服务器或大内存数据库。sysctl 提供了无需重启的运行时内核参数调整能力。本文给出经过生产验证的参数配置,并解释每个参数的含义和调整原因。
sysctl 基础操作
# 查看当前参数值
sysctl net.core.somaxconn
# net.core.somaxconn = 128 ← 默认值太小
# 临时修改(重启后失效)
sysctl -w net.core.somaxconn=65535
# 查看所有参数
sysctl -a
sysctl -a | grep net.ipv4.tcp
# 永久修改(写入配置文件)
echo "net.core.somaxconn = 65535" >> /etc/sysctl.conf
# 或者推荐用 drop-in 文件(避免修改主文件)
echo "net.core.somaxconn = 65535" > /etc/sysctl.d/99-production.conf
# 重新加载配置文件(不重启生效)
sysctl -p /etc/sysctl.d/99-production.conf
sysctl --system # 加载所有 /etc/sysctl.d/*.conf
# 验证生效
sysctl net.core.somaxconn
# net.core.somaxconn = 65535
Web 服务器优化配置
适用于:Nginx、Caddy、Node.js 高并发场景(万级以上 QPS)
cat > /etc/sysctl.d/99-webserver.conf << 'EOF'
# ============================
# 文件描述符
# ============================
# 系统级别最大文件句柄数(默认 9223372036854775807,一般够用)
fs.file-max = 2097152
# ============================
# 网络 - 连接队列
# ============================
# listen() 的全连接队列大小(三次握手完成后排队等待 accept 的连接数)
# 默认 128,高并发场景需要加大,否则 SYN 包堆积
net.core.somaxconn = 65535
# 半连接队列(SYN 队列,收到 SYN 未完成握手的连接数)
net.ipv4.tcp_max_syn_backlog = 65535
# 网卡接收队列长度(网卡收到包、内核处理之前的队列)
net.core.netdev_max_backlog = 65535
# ============================
# 网络 - TCP 连接复用
# ============================
# 启用 TIME_WAIT 连接复用(高并发时 TIME_WAIT 连接会占满端口)
net.ipv4.tcp_tw_reuse = 1
# FIN_WAIT2 超时时间(默认 60s,缩短释放资源更快)
net.ipv4.tcp_fin_timeout = 15
# TIME_WAIT 最大数量(超过则直接回收)
net.ipv4.tcp_max_tw_buckets = 262144
# ============================
# 网络 - TCP 缓冲区
# ============================
# TCP 接收缓冲区(min, default, max,单位字节)
# 增大 max 提高高带宽连接的吞吐量
net.ipv4.tcp_rmem = 4096 87380 16777216
# TCP 发送缓冲区
net.ipv4.tcp_wmem = 4096 65536 16777216
# Socket 接收缓冲区(非 TCP)
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
# Socket 发送缓冲区
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
# ============================
# 网络 - 端口范围
# ============================
# 客户端连接时可用的本地端口范围(扩大可用端口数)
net.ipv4.ip_local_port_range = 1024 65535
# ============================
# 网络 - TCP 保活
# ============================
# TCP KeepAlive 探测间隔(默认 75s,Nginx upstream 场景调短)
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# ============================
# 网络 - 其他
# ============================
# 启用 TCP Fast Open(减少握手延迟)
net.ipv4.tcp_fastopen = 3
# 防止 SYN Flood 攻击(生产必开)
net.ipv4.tcp_syncookies = 1
# ============================
# 内存 - 虚拟内存
# ============================
# 控制系统在内存不足时使用 swap 的倾向(0=优先用内存,100=积极用swap)
# Web 服务器设低值,避免 swap 导致延迟飙升
vm.swappiness = 10
# 脏页刷新阈值(内存中未写回磁盘的数据比例)
# 降低可以减少 write() 突然阻塞(PageCache 刷盘风暴)
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
EOF
sysctl -p /etc/sysctl.d/99-webserver.conf
数据库服务器优化配置
适用于:MySQL、PostgreSQL、Redis 等数据库服务器
cat > /etc/sysctl.d/99-database.conf << 'EOF'
# ============================
# 内存 - 共享内存(PostgreSQL 核心需求)
# ============================
# 共享内存段最大字节数(PostgreSQL shared_buffers 不能超过此值)
kernel.shmmax = 68719476736 # 64GB(设为物理内存的 50-75%)
# 系统所有共享内存段总量
kernel.shmall = 4294967296 # 以内存页为单位(4K/页),16TB
# POSIX 共享内存对象(Redis 使用 mmap 时相关)
kernel.shmmni = 4096
# ============================
# 内存 - 页面管理
# ============================
# 禁用透明大页(THP)- 数据库的死敌,会导致 latency 毛刺
# 通过 GRUB 或运行时禁用
# 运行时:
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
# echo never > /sys/kernel/mm/transparent_hugepage/defrag
# swap 使用倾向(数据库内存宝贵,尽量不用 swap)
vm.swappiness = 1
# 脏页:数据库有自己的 IO 管理,减少内核干预
vm.dirty_ratio = 20
vm.dirty_background_ratio = 10
vm.dirty_expire_centisecs = 3000 # 30秒后强制刷新脏页
vm.dirty_writeback_centisecs = 500 # 5秒检查一次脏页
# 内存过提交(MySQL InnoDB 预分配大量内存时需要)
# 0=内核判断, 1=允许过提交, 2=限制过提交
vm.overcommit_memory = 1
# ============================
# 文件系统
# ============================
# 最大打开文件数(数据库可能打开大量数据文件)
fs.file-max = 2097152
fs.aio-max-nr = 1048576 # 异步 IO 最大请求数(MySQL InnoDB 使用)
# ============================
# 网络
# ============================
# 数据库连接通常是长连接,减少端口复用需求
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
# TCP 接收缓冲区(大数据集查询结果需要大缓冲)
net.ipv4.tcp_rmem = 4096 87380 134217728 # max = 128MB
net.ipv4.tcp_wmem = 4096 65536 134217728
# 连接队列
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
EOF
# 禁用透明大页(数据库服务器必做)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 永久禁用 THP(写入 rc.local 或 systemd service)
cat > /etc/systemd/system/disable-thp.service << 'SERVICE'
[Unit]
Description=Disable Transparent Huge Pages (THP)
After=sysinit.target local-fs.target
Before=basic.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
SERVICE
systemctl daemon-reload
systemctl enable --now disable-thp
Redis 专项调优
cat > /etc/sysctl.d/99-redis.conf << 'EOF'
# Redis 官方推荐参数
# 允许内存过提交(Redis 做 BGSAVE 时 fork,需要和父进程一样多的内存)
# 如果不设这个,大内存 Redis 做快照会失败
vm.overcommit_memory = 1
# 禁止内核通知 Redis 内存不足(OOM 时 Redis 会被杀,改为让它自己处理)
# 不推荐改 oom_adj,现代方式是通过 cgroup 控制
# 关闭透明大页(Redis 延迟毛刺的主要原因之一)
# 见上面 disable-thp.service
# 网络 backlog 要与 Redis 配置的 tcp-backlog 匹配
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
EOF
容器环境(Kubernetes 节点)调优
cat > /etc/sysctl.d/99-kubernetes.conf << 'EOF'
# ============================
# K8s 必须开启的参数
# ============================
# 允许 iptables 处理桥接流量(K8s 网络必须)
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
# 允许 IP 转发(K8s Pod 通信必须)
net.ipv4.ip_forward = 1
# ============================
# 高并发 Pod 网络优化
# ============================
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
# 连接追踪表(大量 Pod/Service 场景下可能不够)
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 600
# ============================
# inotify 限制(很多 Pod 的 watch 会耗尽)
# ============================
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512
# ============================
# 内存
# ============================
vm.swappiness = 0 # K8s 建议关 swap(或设 0)
vm.overcommit_memory = 1
EOF
# 加载 br_netfilter 模块(K8s 网络需要)
modprobe br_netfilter
echo br_netfilter > /etc/modules-load.d/br_netfilter.conf
sysctl -p /etc/sysctl.d/99-kubernetes.conf
验证与监控
# 验证参数是否生效
sysctl net.core.somaxconn net.ipv4.tcp_tw_reuse vm.swappiness
# 查看当前 TCP 连接状态分布(排查 TIME_WAIT 过多)
ss -s
# Netid State Recv-Q Send-Q
# Total: 4521
# TCP: 4289 (estab 3872, closed 250, orphaned 8, timewait 200)
# 统计 TIME_WAIT 数量
ss -t | grep -c TIME-WAIT
# 监控文件描述符使用
cat /proc/sys/fs/file-nr
# 23456 0 2097152 ← 已用 / 空闲 / 上限
# 查看系统 dmesg 确认参数调整日志
dmesg | grep -i "TCP\|memory\|nf_conntrack" | tail -20
参数调整原则
一些经验总结:
不要盲目复制别人的配置: 同一台机器跑 Web 服务和跑数据库的最优参数完全不同,甚至相反。
改一个参数观察一个参数: 批量改完没办法定位是哪个参数起了作用(或造成了问题)。
vm.dirty_ratio 调低不是万能的: 太低会导致写密集场景频繁触发脏页回写,反而影响性能。
net.ipv4.tcp_tw_recycle 已被删除: Linux 4.12 移除了这个参数,使用它会报错,不要在新系统使用。
透明大页(THP)几乎对所有数据库有害: MySQL、PostgreSQL、Redis、MongoDB 官方文档都推荐关闭。
小结
sysctl 调优的本质是“让内核行为更适配你的业务模式”。Web 服务器的核心优化是网络栈:增大连接队列、TCP 端口复用、缩短 TIME_WAIT;数据库服务器的核心优化是内存管理:禁用 THP、减少 swap 使用、给数据库更稳定的内存访问路径;K8s 节点的优化是确保所有网络基础参数正确、inotify 不被耗尽、连接追踪表足够大。每次变更后要监控业务指标,用数据验证效果。
