根本原因是四层限制未对齐——内核fs.file-max、用户limits、进程启动环境、Nginx自身配置任一层卡在默认值(如1024)即导致整体失效;需逐层检查并同步调优。

根本原因不是“改得不够大”,而是四层限制没对齐——内核、用户、进程启动环境、Nginx自身配置,任意一层卡在默认值(比如 1024),就会让其他层的调整全部失效。
系统全局上限(fs.file-max)设低了
即使 ulimit -n 显示 65535,worker 进程也显示 65535,但如果 /proc/sys/fs/file-max 只有 10240,系统总池子就那么小。所有进程加起来不能超这个数,高并发时很快耗尽。常见于未调优的云服务器或容器环境,尤其当 nginx worker_processes × worker_connections × 2(含日志、临时文件等)接近甚至超过 file-max 时,必然报错。
- 查当前值:cat /proc/sys/fs/file-max
- 临时调高:sysctl -w fs.file-max=2097152
- 永久生效:在 /etc/sysctl.conf 加 fs.file-max = 2097152,再运行 sysctl -p
limits.conf 修改后未真正生效
写进 /etc/security/limits.conf 不等于生效。最常漏掉三件事:
-
没指定 nginx 用户:用 * 是全局,但若 Nginx 以 nginx 用户运行,必须显式加两行:
nginx soft nofile 65535
nginx hard nofile 65535 -
PAM 模块未启用:检查 /etc/pam.d/common-session(Ubuntu/Debian)或 /etc/pam.d/login(CentOS/RHEL),确认存在
session required pam_limits.so -
systemd 启动覆盖了 limits:现代系统多用 systemd 管理 Nginx,/etc/systemd/system/nginx.service.d/override.conf 中若设置了 LimitNOFILE,它会优先于 limits.conf;没配则需补上并重载:
systemctl daemon-reload && systemctl restart nginx
Nginx worker 进程实际继承的不是你预期的限制
ulimit -n 查的是当前 shell 的软限,而 Nginx master 进程启动时读取的是其用户(如 nginx)的 limits,worker 进程又受 worker_rlimit_nofile 约束——但它不能高于用户 hard limit,否则静默降级。
- 查 master 实际限制:cat /proc/$(cat /var/run/nginx.pid)/limits | grep "Max open files"
- 查 worker 实际限制:ps --ppid $(cat /var/run/nginx.pid) -o %p | sed '1d' | xargs -I{} cat /proc/{}/limits | grep "Max open files"
- 若 worker 显示仍是 1024 4096,说明上面某一层没打通,别急着调 worker_connections
worker_rlimit_nofile 和 worker_connections 配比错误
worker_rlimit_nofile 是每个 worker 进程能打开的**所有文件描述符总数**(含 socket、日志、配置、临时文件等);worker_connections 是它能处理的**并发网络连接数**。后者必须 ≤ 前者,且要留出余量(建议 ≤ 80%)。
- 例如:worker_rlimit_nofile 设为 65535,worker_connections 就不应设为 65535,而应设为 50000 或更低
- 同时确认 worker_processes 值(如 auto 或具体数字),因为总 FD 消耗 ≈ worker_processes × (worker_connections + 日志/静态文件等开销)
- 公式底线:worker_rlimit_nofile ≥ worker_connections × 1.2(保守预留)


















