生产机 sysctl 到底调哪些——10 个必调内核参数清单
本文目录
先说结论
第一条:生产机 sysctl 必须显式配置,不能靠发行版默认——CentOS/Ubuntu 默认值保守,为桌面场景服务,和高并发服务端需求差距很大。
第二条:调参分 4 类:网络栈、文件句柄、内存/swap、进程数量。每一类对应一些明确的高频场景。
第三条:所有调参必须写进 /etc/sysctl.d/99-custom.conf 持久化,运行时 sysctl -p 生效,别直接 echo /proc 临时改——重启就没了。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
某短视频平台一个 Kafka 集群,上线初期吞吐一直上不去——单机理论能扛 80 万 QPS,实测到 30 万就开始 TIME_WAIT 堆积、accept 队列溢出、文件句柄报警,像是硬件不行。但我们知道硬件是没问题的,最后发现是 /etc/sysctl.conf 除了系统默认值什么都没动。改完 10 个内核参数重启,吞吐直接冲到 90 万。
这道题考的是'你有没有真正给生产机做过初始化'。很多候选人能背出几个名字(tcp_tw_reuse、somaxconn),但说不清各自的作用和风险——这种半懂不懂的状态在生产上是最危险的。
10 个必调参数完整清单
bash - /etc/sysctl.d/99-custom.conf
# ============ 网络连接层 ============
# 1) TCP 半连接队列大小(SYN 收到但未握手完成)
net.ipv4.tcp_max_syn_backlog = 65535
# 默认 128-2048,高并发服务端直接拉到 65535
# 过小的症状:客户端连接偶发 SYN 丢失,netstat -s 看 SYNs to LISTEN dropped
# 2) accept 队列大小(握手完成等 accept)
net.core.somaxconn = 65535
# 默认 128,几乎所有生产服务都要改
# 过小的症状:dmesg 有 'possible SYN flooding on port X'
# 配合应用层 listen(fd, 65535) 一起改才生效
# 3) TIME_WAIT 快速回收(复用端口)
net.ipv4.tcp_tw_reuse = 1
# 允许 TIME_WAIT 连接被同 socket 复用(客户端侧)
# 注意:tcp_tw_recycle 在 4.12+ 内核已被移除,别再用(NAT 环境下是惨案)
# 4) 本地端口范围(客户端连出能用的端口)
net.ipv4.ip_local_port_range = 10240 65535
# 默认 32768-60999,约 2.8 万个
# Kafka/Kafka Connect 这种大量做主动连接的客户端必调
# 5) TCP 缓冲区动态范围
net.core.rmem_max = 134217728 # 128M
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
# 高 BDP(带宽-延迟积)场景才需要调大,跨区传输尤其重要
# ============ 文件句柄 & 进程数 ============
# 6) 系统最大 file descriptor 数
fs.file-max = 2097152
# 默认 ~8 万,高并发服务端远远不够
# 配合 /etc/security/limits.conf 的 nofile 一起改才能真正生效
# 7) 单 pid 可监控的 inotify
fs.inotify.max_user_watches = 524288
# 默认 8192,跑 Elastic/Prometheus/K8s 的机器必调
# ============ 内存 ============
# 8) 避免不必要的 swap
vm.swappiness = 1
# 默认 60,延迟敏感服务必改
# 9) overcommit 策略
vm.overcommit_memory = 1
# 0 = 启发式(默认)
# 1 = 总是允许(Redis 官方建议)
# 2 = 严格(不超 RAM + swap * ratio),容易 fork 失败
# 10) 脏页写回阈值
vm.dirty_ratio = 20
vm.dirty_background_ratio = 5
# 默认 20/10,写密集场景下降 background 比例让 writeback 更平滑
执行方式:sysctl -p /etc/sysctl.d/99-custom.conf 立即生效,同时写进文件确保重启后仍然应用。一定要放到 /etc/sysctl.d/ 目录下而不是直接改 /etc/sysctl.conf,后者会被系统升级覆盖。
配合参数:文件句柄的 limits.conf
fs.file-max 是内核全局限制,但每个用户/进程还有自己的 soft/hard 限制,这俩必须一起改:
bash - /etc/security/limits.d/99-custom.conf
# 格式:<domain> <type> <item> <value>
# 所有用户的文件句柄
* soft nofile 1048576
* hard nofile 1048576
# 所有用户的进程数
* soft nproc unlimited
* hard nproc unlimited
# 核心转储(生产关掉防磁盘被打爆)
* soft core 0
* hard core 0
# 锁内存(MySQL/Redis memlock 需要)
mysql soft memlock unlimited
mysql hard memlock unlimited
# 改完必须重新登录 / 重启服务才生效
# 验证:
ulimit -n # 看当前 nofile
cat /proc/<pid>/limits # 看已运行进程的 limit
systemd 的坑:如果服务是 systemd 管理的,limits.conf 可能不生效!systemd 有自己的 LimitNOFILE 设置,必须在 unit 文件里加:[Service] 下面 LimitNOFILE=1048576。否则你改了 limits.conf 但服务启动后 ulimit -n 还是 1024——这个坑我见过太多人踩。
场景还原:那个冲不上 80 万 QPS 的 Kafka
某短视频平台那次 Kafka 上限调优,症状和改动完整记录:
# 症状 1:吞吐打到 30 万时 producer 开始报 LEADER_NOT_AVAILABLE
# 看 broker 日志
dmesg | tail
# TCP: request_sock_TCP: Possible SYN flooding on port 9092. Dropping request.
# ← 经典 accept 队列打满
# 确认 somaxconn 和应用 backlog 都很小
cat /proc/sys/net/core/somaxconn
# 128 ← 坑
ss -ltn sport = :9092
# State Recv-Q Send-Q Local Address:Port
# LISTEN 129 128 *:9092
# Recv-Q 已经打满 backlog
# 症状 2:连接数涨到 1 万时报 too many open files
ulimit -n
# 1024 ← 发行版默认
# 症状 3:客户端大量 TIME_WAIT 吃光本地端口
ss -s
# TCP: 1234 (estab 456, closed 5432, orphaned 12, timewait 25000/0)
# 三处同时改:
cat > /etc/sysctl.d/99-kafka.conf <<EOF
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10240 65535
fs.file-max = 2097152
vm.swappiness = 1
EOF
sysctl -p /etc/sysctl.d/99-kafka.conf
# systemd unit 里加 LimitNOFILE
systemctl edit kafka
# [Service]
# LimitNOFILE=1048576
systemctl daemon-reload && systemctl restart kafka
改完后单机吞吐从 30 万直接上到 90 万,QPS 瓶颈消失,整个集群按预期运转。这种「默认值没改所以跑不满硬件」的故事,在生产上太常见了——每次新机器上线忘了调 sysctl,都会踩一次。
参数优先级速查
| 参数 | 默认 | 推荐 | 影响场景 |
|---|---|---|---|
| somaxconn | 128 | 65535 | 所有 TCP 服务端 |
| tcp_max_syn_backlog | 1024 | 65535 | 高并发入站 |
| tcp_tw_reuse | 0 | 1 | 客户端大量短连接 |
| ip_local_port_range | 32768-60999 | 10240-65535 | 客户端连出多 |
| fs.file-max | ~80k | 2M | 所有服务端 |
| nofile (limits) | 1024 | 1048576 | 所有服务 |
| swappiness | 60 | 1 | 延迟敏感服务 |
| overcommit_memory | 0 | 1 | Redis/fork 多 |
| inotify.max_user_watches | 8192 | 524288 | Prometheus/ES/K8s |
| tcp_fin_timeout | 60 | 15 | 客户端短连接 |
面试高频追问
追问一:为什么 tcp_tw_recycle 在 4.12+ 内核被移除了?
因为它在 NAT 环境下是灾难。tcp_tw_recycle 开启后,内核会根据源 IP + 时间戳快速回收 TIME_WAIT,但如果多个客户端在同一个 NAT 后面(公网出口是同一个 IP),它们的时间戳不同步,内核会把晚到的合法 SYN 包当作'重复的旧包'直接丢弃,表现为大量客户端间歇性连接失败,问题非常难排查。Linux 社区从 4.12 开始直接删掉这个参数——任何面试你看到有人建议开 tcp_tw_recycle,基本可以确定对方没踩过生产坑。现在正确的做法是只用 tcp_tw_reuse,它不依赖时间戳,只管客户端出站场景,没有 NAT 副作用。
追问二:调大 somaxconn 必须同时改应用吗?
对。somaxconn 只是内核的上限,应用 listen(fd, backlog) 时传的那个 backlog 参数是应用自己指定的队列长度。内核最终用的是 min(somaxconn, 应用传的 backlog)。如果应用传的是 50(很多框架默认值),你把 somaxconn 调到 65535 也没用——内核仍然用 50。Nginx 有 listen 80 backlog=65535;Tomcat 有 server.xml 的 acceptCount;Java 的 ServerSocket 默认 50,要显式 new ServerSocket(port, 65535)。两边都要改才真生效,这是常见坑。
追问三:你怎么确认 sysctl 改完的参数真的生效了?
最直接的是 sysctl -a | grep <参数名> 看当前值,但这只能证明内核参数生效——文件句柄、进程数这种要看 /proc/
实战踩坑:那次 systemd 坑了半天
某短视频平台那次 Kafka 调参还有一个插曲:我们按标准流程改了 sysctl.conf + limits.conf,service restart 后验证 ulimit -n 却还是 1024。查了半个小时才发现是 systemd 的问题——systemd 启动的服务完全不走 /etc/security/limits.conf,要在 unit 文件里单独设置 LimitNOFILE。
bash - 完整的 systemd unit 示例
# /etc/systemd/system/kafka.service
[Unit]
Description=Kafka
After=network.target
[Service]
Type=simple
User=kafka
ExecStart=/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties
Restart=on-failure
# 以下都是 systemd 特有限制,不看 limits.conf
LimitNOFILE=1048576 # 文件句柄
LimitNPROC=unlimited # 进程数
LimitMEMLOCK=infinity # 锁内存
LimitCORE=0 # 禁 core dump
# OOM 保护(重要服务让 OOM killer 优先杀别人)
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
复盘:这种'改了但是不生效'的坑会把人搞崩溃。后来我把完整的'服务端机器初始化清单'写成了 Ansible playbook,新机器上线一次跑完:sysctl + limits + systemd unit template + 常用工具(htop/iftop/iotop/nethogs/smem)。这个 playbook 跑 3 分钟,省掉无数半夜的排错时间。
总结
sysctl 调参看似琐碎,其实是生产机的'体检报告'——默认值适合桌面,你得自己调到适合服务端的状态。10 个参数抄下来背熟、写进 Ansible role 里复用,是大数据/运维岗的基本功。面试时你能讲出 somaxconn vs 应用 backlog 的联动、tcp_tw_recycle 为什么在 4.12+ 被删、systemd 不走 limits.conf 这三点,基本就是'调过生产'的铁证。
下一篇预告:OOM Killer 为什么总是杀错进程——oom_score / overcommit / cgroup 联合解读。
你生产机上 sysctl 调过哪些特殊参数?评论区互相抄作业。
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长