“too many open files”本质是系统文件描述符(fd)四层限制未对齐,需同步调优内核fs.file-max、用户limits.conf、systemd limitnofile及nginx.conf中worker_rlimit_nofile与worker_connections,缺一不可。

日志写入报错如 open() "/var/log/nginx/access.log" failed (24: Too many open files),本质不是日志配置错了,而是系统文件描述符(FD)资源耗尽——Nginx 既要处理网络连接、又要打开日志文件、还要读静态资源,所有这些都共用同一套 FD 限制。必须从内核层开始打通四层限制,否则改了 nginx.conf 或只跑 ulimit 命令,照样报错。
查清当前各层实际生效值
别凭经验猜,直接看进程真实限制:
- 系统全局上限:
cat /proc/sys/fs/file-max(建议 ≥ 1048576,高并发环境更稳妥) - Nginx 用户软/硬限制:
sudo -u nginx bash -c "ulimit -Sn && ulimit -Hn" - Nginx 主进程限制:
cat /proc/$(cat /var/run/nginx.pid)/limits | grep "Max open files" - Nginx 工作进程限制(关键):
ps --ppid $(cat /var/run/nginx.pid) -o %p | sed '1d' | xargs -I{} cat /proc/{}/limits | grep "Max open files"
同步调优四层限制(缺一不可)
只调其中一层,比如光改 worker_rlimit_nofile,其他层卡在 1024,Nginx 依然只能用 1024 个 FD:
-
内核级:执行
sudo sysctl -w fs.file-max=1048576,再写入/etc/sysctl.conf持久化:echo "fs.file-max = 1048576" | sudo tee -a /etc/sysctl.conf && sudo sysctl -p -
用户级(PAM):编辑
/etc/security/limits.conf,添加(假设 Nginx 以nginx用户运行):nginx soft nofile 65535nginx hard nofile 65535
确认/etc/pam.d/common-session(Ubuntu/Debian)或/etc/pam.d/login(CentOS/RHEL)中含session required pam_limits.so -
systemd 启动环境:执行
sudo systemctl edit nginx,在[Service]下添加:LimitNOFILE=65535
然后重载并重启:sudo systemctl daemon-reload && sudo systemctl restart nginx -
Nginx 自身配置:在
/etc/nginx/nginx.conf全局块添加:worker_rlimit_nofile 65535;
并在events块中确保:worker_connections 4096;(或 8192,但必须 ≤worker_rlimit_nofile)
验证日志写入是否真正恢复
重启后重点检查两点:
- worker 进程的
/proc/*/limits显示类似:Max open files 65535 65535 files - 错误日志不再出现
open() ... failed (24: Too many open files),同时access.log和error.log能持续写入(可用tail -f /var/log/nginx/*.log实时观察) - 顺手检查日志轮转工具(如 logrotate)是否也受限:它运行时若以 root 外的用户执行,也要确认该用户的
ulimit设置
避免常见干扰项
有些现象容易误判为 FD 问题,排查时需排除:
- 磁盘满导致日志写失败(
df -h查空间,df -i查 inode) - 日志目录权限不对(
ls -ld /var/log/nginx,确保 nginx 用户有写权限) - SELinux 或 AppArmor 拦截写入(临时设为 permissive 模式测试)
- logrotate 执行时未发送 HUP 信号,Nginx 仍往已重命名的旧文件句柄写(应在 rotate 配置中加
create和sharedscripts,并用postrotate nginx -s reload)











