FD耗尽是Nginx stub_status返回500/连接拒绝的常见原因,需检查主进程FD使用量与limit上限是否接近,并验证系统、用户及systemd级限制配置,同时排查日志、upstream、临时文件等隐式FD消耗。

当 Nginx 的 stub_status 接口(如 /nginx_status)突然返回 500、连接拒绝或空响应,而 Nginx 进程仍在运行、其他请求正常时,文件描述符(file descriptor, FD)耗尽是常见原因之一。Nginx 在处理每个客户端连接、日志文件、上游连接、临时文件等时都会占用 FD,一旦达到系统或进程限制,就无法新建 socket(包括 stub_status 的响应 socket),导致监控失效。
确认是否为 FD 耗尽问题
直接检查 Nginx 主进程和工作进程的当前 FD 使用量与上限:
- 查 Nginx 主进程 PID:
ps aux | grep "nginx: master process",记下 PID(如1234) - 查看该进程打开的 FD 数量:
ls -l /proc/1234/fd/ | wc -l - 查看该进程的 FD 上限:
cat /proc/1234/limits | grep "Max open files" - 对比两者:若已用数量接近或等于 soft limit(如 1024/1024),基本可判定为 FD 不足
- 补充验证:用
lsof -p 1234 | wc -l看打开文件总数(含 socket、log、tmp 等),并注意是否有大量socket:[*]或anon_inode
检查系统级和用户级 FD 限制
Nginx 启动时继承的是启动用户的 limits,而非 root 的配置。常见误区是只改了 /etc/security/limits.conf 却未生效:
- 确认 Nginx 是以哪个用户运行:
ps aux | grep nginx(通常为www-data或nginx) - 检查该用户在
/etc/security/limits.conf中的设置,例如:
www-data soft nofile 65536
www-data hard nofile 65536 - 确保 PAM limits 已启用:检查
/etc/pam.d/common-session是否包含session required pam_limits.so - 如果是 systemd 启动(如 Ubuntu 16.04+/CentOS 7+),还需覆盖 systemd service 配置:
创建/etc/systemd/system/nginx.service.d/override.conf,加入:
[Service]
LimitNOFILE=65536
然后执行systemctl daemon-reload && systemctl restart nginx
检查 Nginx 配置中隐式消耗 FD 的行为
某些配置会显著增加 FD 持有量,尤其在高并发或异常场景下:
-
access_log / error_log 使用 syslog 或 pipe:每条日志可能触发新 socket 连接(如
syslog:server=127.0.0.1:514)或管道 fd,建议改用文件路径 + logrotate -
upstream keepalive 连接数过高且未及时回收:例如
keepalive 1000;但后端响应慢或丢包,导致大量 idle 连接堆积在 worker 进程中 - 大量使用 include 或 map 指令加载大文件:虽不常驻 FD,但 reload 时可能瞬时打开过多文件
- client_body_temp_path / proxy_temp_path 权限错误:Nginx 可能反复尝试创建临时文件失败,产生大量报错并卡住 FD 分配逻辑
快速验证与临时恢复
在定位期间,可做以下操作快速验证和缓解:
- 重启 Nginx(释放所有 FD):
nginx -s reload或systemctl reload nginx;若重启后 stub_status 立即恢复,高度提示 FD 泄漏或耗尽 - 临时提高当前运行进程的 FD 限制(仅调试用,不持久):
prlimit --nofile=65536:65536 -p 1234(需 root,部分内核版本支持) - 用
ss -s查看全系统 socket 统计,重点关注total:和timewait:数量;若 time-wait 过多且未复用,可能因net.ipv4.tcp_tw_reuse关闭导致 FD 占用延长 - 开启 Nginx debug 日志(慎用):
error_log /var/log/nginx/error.log debug;,搜索"open() "/dev/null" failed"或"accept() failed (24: Too many open files)"


















