“Too many open files”报错源于文件描述符资源耗尽或泄露,需分步排查系统级、用户级、systemd级和Nginx进程级四层限制,并检查open_file_cache、ssl_session_cache等易滞留fd的配置。

遇到“Too many open files”报错,说明 Nginx 已触达系统对文件描述符(fd)的限制阈值。这不是配置没加够的问题,而是四层资源限制未对齐、或连接/文件生命周期管理失当导致的资源滞留。排查必须分步验证、逐层定位,不能靠猜。
先确认是不是真耗尽,还是真泄露
耗尽是“上限太低”,泄露是“该关没关”。两者现象相似但根因不同:
- 执行 lsof -p $(pgrep -f "nginx: worker" | head -1) | wc -l,每分钟记录一次。若数值稳定在
worker_connections × 1.2附近(含监听套接字、日志句柄、缓存句柄等),属正常负载;若持续单向上涨、重启后快速回升,就是泄露 - 查 /proc/sys/fs/file-nr:输出三列数字,第三列是系统总上限(
file-max),第二列是当前已分配数。若第二列持续逼近第三列,说明系统级池子快枯竭,需调高fs.file-max - 对比 cat /proc/$(pgrep nginx | head -1)/limits | grep "Max open files" 中的 soft limit 和当前打开数。差值仍大于 1000 却持续报错,基本可排除容量不足,转向配置排查
四层限制必须全部查清并同步对齐
Linux 中 fd 限制有四道关卡,Nginx 实际生效值取其中最小者。任一层卡住,调其他都白搭:
-
系统级:运行
cat /proc/sys/fs/file-max,建议 ≥ 1048576(100 万)。若不足,写入fs.file-max = 2097152到/etc/sysctl.conf,再sysctl -p -
用户级:用 Nginx 实际运行用户(如
nginx或www-data)执行sudo -u nginx bash -c "ulimit -Sn; ulimit -Hn"。默认常为 1024,应设为 65536。编辑/etc/security/limits.conf,添加:nginx soft nofile 65536nginx hard nofile 65536 -
systemd 级(现代发行版默认启用):运行
systemctl show nginx | grep LimitNOFILE。若为空或远低于 65536,需创建/etc/systemd/system/nginx.service.d/override.conf,内容为:[Service]LimitNOFILE=65536
然后systemctl daemon-reload && systemctl restart nginx -
Nginx 进程级:在
nginx.conf的最外层(events块之前、http块之外)添加:worker_rlimit_nofile 65536;
注意:不能写在http或server块内,否则启动失败
重点检查易滞留 fd 的配置项
很多“耗尽”其实是以下配置与业务不匹配造成的 fd 滞留:
-
open_file_cache:若
inactive设为 300s,而大量请求访问短命静态资源(如图标、小 JS),缓存条目不淘汰,对应 fd 就不释放。建议设为20s–60s,并开启open_file_cache_errors on -
ssl_session_cache:命中率低于 70%(可通过
$ssl_session_reused变量统计),说明缓存区过小或超时不合理,会退化为全握手,临时占用更多 fd 和内存。可扩容共享内存区或延长ssl_session_timeout -
access_log:路径含变量(如
$host、$request_uri)会导致每个唯一值新建日志文件,fd 数随请求多样性线性增长。建议固定路径,或关闭日志:access_log off; -
proxy_buffering:设为
off时,Nginx 会为每个 upstream 响应预分配大缓冲区,若响应延迟或中断,关联 fd 易堆积。保持on,并合理设置proxy_buffer_size和proxy_buffers
验证与收尾动作
改完配置后,务必按顺序操作:
- 执行
nginx -t确认语法无误 - 重载服务:
systemctl reload nginx(避免中断连接) - 立即检查生效值:
cat /proc/$(pgrep nginx | head -1)/limits | grep "Max open files",确认 soft/hard 均为 65536 - 观察
error.log是否还有accept() failed (24: Too many open files)或socket() failed - 用
lsof -p $(pgrep nginx | head -1) | wc -l对比前后变化,持续监控 10 分钟看趋势



















