删了缓存目录后句柄仍存在,是因为Nginx持有文件描述符(fd),Linux内核在fd关闭前不释放inode和磁盘空间;需用lsof确认deleted句柄,通过nginx -s reload回收,长期应避免rm -rf并合理配置open_file_cache_valid与min_uses。

当 open_file_cache 缓存的目录被意外删除(如 rm -rf 清空了缓存路径),Nginx 不会立即报错,但会持续持有已打开的文件句柄(file descriptor),导致磁盘空间无法释放、lsof 显示大量 deleted 状态句柄,甚至引发 Too many open files 错误。这不是配置失效问题,而是内核级文件引用行为所致。
为什么删目录后句柄仍存在
Nginx 启用 open_file_cache 后,会对频繁访问的文件(如静态资源)执行 open() 并长期持有 fd。Linux 中,只要进程还持有该 fd,即使对应文件或其所在目录被 unlink 或 rmdir,内核也不会真正回收 inode 和磁盘空间——数据块一直保留,直到 Nginx 主动 close() 或进程退出。
典型表现:
-
lsof -p $(cat /var/run/nginx.pid) | grep deleted显示大量/path/to/cache/xxx (deleted) -
df显示磁盘空间未释放,但du -sh /path/to/cache显示为空 -
ulimit -n接近上限,新请求返回500或日志出现open() failed (24: Too many open files)
如何快速确认是否是此问题
运行以下命令组合判断:
-
ls -la /proc/$(cat /var/run/nginx.pid)/fd/ | grep deleted | wc -l—— 统计已删除但未关闭的 fd 数量 -
cat /proc/$(cat /var/run/nginx.pid)/limits | grep "Max open files"—— 查看当前限制 -
nginx -t && nginx -s reload—— 若 reload 后lsof | grep deleted数量明显下降,基本可定位为此类缓存残留
临时缓解与长期规避方案
临时缓解(不中断服务):
- 执行
nginx -s reload:worker 进程重启后会重新打开文件,旧进程自然退出,所有残留 fd 被内核回收(注意:reload 不等于 restart,不会丢连接) - 若 reload 无效(如 master 拒绝 reload),可
kill -USR2+kill -WINCH手动滚动升级 worker,效果等同
长期规避:
- 避免直接
rm -rf缓存目录;改用find /path/to/cache -type f -mmin +60 -delete清理过期文件 - 禁用
open_file_cache的目录级缓存逻辑:不将缓存路径设为实际业务目录(如不要设成/usr/share/nginx/html),而使用独立 tmpfs 或专用子目录(如/var/tmp/nginx_cache) - 启用
open_file_cache_valid和open_file_cache_min_uses合理值(如60s和2),让缓存更积极淘汰,降低长持 fd 概率
补充:验证缓存是否真在用该目录
可通过调试日志确认:
- 临时添加
error_log /var/log/nginx/debug.log debug_open_file_cache; -
nginx -s reload后触发几次静态资源请求 - 检查日志中是否出现
open_file_cache: file ... was not found, updated或open_file_cache: file ... found in cache—— 表明缓存机制确实在工作


















