nginx文件描述符泄露本质是“该关没关”的资源缓慢堆积,需通过lsof持续观察、file-nr核对及limits比对确认真泄露;重点排查open_file_cache、ssl_session_cache、proxy_buffering等配置,对齐后端keepalive超时,并启用keepalive复用与socket保活。

排查 Nginx 文件描述符泄露,核心是识别“该关没关”的连接或文件资源。它不是瞬间爆满,而是缓慢堆积——比如 lsof 统计数每分钟涨几十、重启后几小时内又快速回升,同时 error.log 持续出现 accept() failed (24: Too many open files)。真正要盯的不是上限调多大,而是哪些配置会让句柄卡在半开状态不释放。
重点排查易滞留句柄的 Nginx 配置项
多数“泄露”其实是配置与业务节奏错配造成的资源滞留,而非代码缺陷:
-
open_file_cache:启用后若
inactive时间设得过大(如 300s),而业务大量访问短命静态资源(如图标、小 JS),缓存条目长期不淘汰,对应文件句柄就无法释放。建议设为 20–60s,并开启open_file_cache_errors on主动剔除失效项 -
ssl_session_cache:共享内存区满时,新 TLS 握手会退化为全握手,不仅 CPU 升高,还会临时分配堆内存和 socket 句柄。检查
$ssl_session_reused变量统计命中率,低于 70% 就需扩容 cache 或调高ssl_session_timeout(如设为 4h) -
proxy_buffering off:关闭缓冲后,Nginx 会为每个 upstream 响应预分配大缓冲区(可能达几 MB),若后端响应体大、延迟高或中途断连,这些缓冲区及关联 fd 易堆积。建议保持
on,并合理设置proxy_buffer_size和proxy_buffers -
access_log 路径含变量:如使用
$host、$request_uri等动态字段,每次匹配都可能打开新日志文件,句柄数随请求多样性线性增长
注意系统与进程级限制干扰
别把限制不足误判为泄露:
- 执行
lsof -p $(pgrep -f "nginx: worker" | head -1) | wc -l连续观察 5 分钟:若数值稳定在worker_connections × 1.2附近,属正常;若持续上涨且不回落,才是泄露信号 - 用
cat /proc/sys/fs/file-nr查看系统已分配句柄是否逼近file-max,排除全局池枯竭 - 对比
cat /proc/[pid]/limits | grep "Max open files"中 soft limit 与当前打开数,差值仍大于 500 却还在涨,基本可锁定配置或模块问题
第三方模块与自定义逻辑是高危区
尤其在源码编译环境中,泄漏常来自外部扩展:
- Lua 脚本、sub_filter、headers-more 等模块若未正确注册 cleanup 回调,或把 long-lived 数据挂到 request pool 上,会导致内存与句柄双泄漏
- 检查是否使用了
ngx_palloc_large分配但未释放的大块内存,Valgrind 报告中若调用栈含模块名(如ngx_http_subs_body_filter),基本可定位 - 逐个注释
load_module指令,配合ps aux --sort=-%mem和lsof -p PID | wc -l观察变化,能快速隔离问题模块
不复杂但容易忽略:句柄泄露往往藏在“看起来很合理”的配置里,比如把 ssl_session_timeout 设成 8h 却只服务短连接 API,或者用 $host 写 access_log 却没意识到每天新增上百个子域名。关键是让配置节奏跟上真实流量模式。











