直接用 rm -rf 清理 nginx 缓存目录会引发 worker 进程句柄异常,因已删除文件的 inode 和 fd 仍被持有,导致 accept() failed、cpu 升高、命中率下降;应改用 ngx_cache_purge 模块精准清除或设置 inactive 自动淘汰。

直接用 rm -rf 清理 Nginx 缓存目录(如 /var/cache/nginx/)看似简单,但极易引发 worker 进程句柄异常——表现为 accept() failed (24: Too many open files)、CPU 持续偏高、缓存命中率骤降甚至服务短暂不可用。这不是“删错了”,而是 Linux 文件系统机制与 Nginx 缓存管理逻辑冲突导致的资源滞留。
为什么 rm 会触发句柄异常?
Nginx 的 proxy_cache 和 fastcgi_cache 在运行中会持续打开缓存文件进行读写、校验和元数据更新。这些文件虽被 rm 从目录树中移除,但只要 worker 进程仍持有其文件描述符(fd),该文件在磁盘上就**不会真正释放空间**,其 inode 依然存在,fd 也继续占用。此时:
- 新请求尝试访问同名缓存条目时,Nginx 可能因路径不存在而重建缓存,但旧 fd 未关闭,导致句柄数虚高
- 部分缓存文件被删后,Nginx 在后续清理或校验中反复尝试
stat()或open()已删除路径,失败日志堆积且触发重试逻辑,进一步拖慢 worker - 若缓存目录下有大量子目录(如按 hash 分层),
rm -rf本身会阻塞 I/O,期间 worker 可能因等待磁盘响应而卡住,间接加剧句柄积压
如何安全排查 rm 后的句柄异常?
别急着重启,先定位真实影响范围:
- 查当前 worker 打开的已删除文件:
lsof -p $(pgrep -f "nginx: worker") | grep deleted。输出中若出现大量/var/cache/nginx/... (deleted)行,说明问题已发生 - 对比句柄总数与活跃连接:
lsof -p [worker_pid] | wc -l和ss -s | grep "tcp:"。若前者远超后者(例如 >5 倍),基本确认是缓存文件残留导致 fd 滞留 - 检查内核是否已回收空间:
df -h /var/cache/nginx和du -sh /var/cache/nginx。若df显示空间未释放而du显示为空,正是“已删未释”的典型特征
比 rm 更稳妥的清理方式
避免直接暴力删除,改用 Nginx 原生支持或可控手段:
- 启用
ngx_http_cache_purge_module
-
按 key 计算路径后精准删除:根据你的
proxy_cache_key 规则(如 <code>$scheme$proxy_host$request_uri),用md5sum算出哈希值,再按 Nginx 默认的两级 hash 目录结构(如/a/1b/...)定位并rm单个文件。操作前先kill -USR2重载配置确保 key 规则一致 -
改用版本化缓存路径:在
proxy_cache_path中加入变量,如/var/cache/nginx/v2/。升级时只需切换proxy_cache指向新路径,旧路径可异步清理,完全规避运行中删除
恢复与预防要点
已发生异常时,最有效动作是平滑重启:nginx -s reload 不够,必须 nginx -s stop && nginx。因为 reload 仅新建 worker,旧 worker 仍持有着那些 (deleted) fd;只有彻底 stop,所有 worker 退出,fd 才真正释放。
长期预防的关键是:禁用定时 rm -rf 脚本;所有缓存清理必须走 purge 或路径切换;在 proxy_cache_path 中设置 inactive=60m,让 Nginx 自动淘汰长时间未访问的缓存条目,减少人工干预必要性。











