确认是文件描述符耗尽,需分层排查:若仅部分worker报错,可能是fd泄漏;若全部同步报错且dmesg提示file-max告警,则为内核级总量不足;应立即检查/proc/sys/fs/file-nr、各进程limits及lsof分布,并同步调高sysctl、limits.conf、systemd limitnofile和nginx worker_rlimit_nofile。

看到 error_log 里反复出现 “accept() failed (24: Too many open files)”,基本可以确认是文件句柄(fd)耗尽了。但这个报错只是表象,真正的问题可能在进程、用户或系统层级——不能只改 worker_rlimit_nofile 就完事。
看错误是否集中在个别 worker 进程
如果只有几个 worker(比如 PID 1234、5678)持续报错,其他 worker 正常,说明问题大概率出在该进程内部:
- 可能是连接未释放,比如 upstream keepalive 配置不当、长连接堆积或 close_wait 大量存在
- 也可能是日志文件打开过多(如按小时切分但未 reload)、open_file_cache 缓存了太多文件句柄
- 还可能是第三方模块或 Lua 脚本中 fd 泄漏(如 socket 或 file 没调 close)
查系统级 fd 使用是否逼近上限
执行 cat /proc/sys/fs/file-nr,重点关注第二列(当前活跃使用量)与第三列(fs.file-max)的比值:
- 若第二列长期超过第三列的 80%,说明内核全局资源紧张,需调高
fs.file-max - 若第二列只有几百或几千,但 error_log 仍报错,问题一定不在系统层,要往下查进程限制
- 同时运行
dmesg | grep -i "file.*max\|descriptor",确认是否有内核级告警
确认 nginx 进程实际生效的限制
不要信 ulimit -n,它对 systemd 启动的服务无效。正确做法是:
- 用
systemctl show --property MainPID nginx获取主进程 PID - 运行
cat /proc/<pid>/limits | grep "Max open files"</pid>,看 Soft Limit 值 - 再执行
ls -l /proc/<pid>/fd/ | wc -l</pid>,对比实时占用与限制是否接近 - 若两者接近,说明进程级限制已触顶;若远低于限制却仍报错,可能是
nr_open内核参数不足或存在 memfd 类型句柄异常
同步检查四层配置是否真正生效
nginx 高并发下 fd 耗尽可能性来自某一层没配齐或没生效:
-
系统级:修改
/etc/sysctl.conf中的fs.file-max,然后sysctl -p -
用户级:在
/etc/security/limits.conf中为 nginx 用户设nofile软硬限制 -
systemd 级:编辑
/etc/systemd/system/nginx.service.d/override.conf,加LimitNOFILE=65536 -
nginx 进程级:在 nginx.conf 的 main 块中设
worker_rlimit_nofile 65536,且该值不能超过前几层的软限制











