排查Nginx文件描述符泄漏应分四步:lsof定位泄漏源,fuser快速筛查端口/文件占用,ss分析网络连接态,gdb紧急关闭异常fd;四者协同形成闭环验证。

排查 Nginx 文件描述符泄漏,关键不是堆工具,而是分清角色、抓住时机、验证闭环。lsof 是主眼,fuser 是快筛,ss 专盯网络连接态,gdb 则是最后的“外科手术刀”。四者不互斥,而是在不同阶段各司其职。
lsof:定位泄漏进程与资源类型的主力工具
它是整个排查链的起点和核心,直接反映 Nginx worker 进程当前持有的所有文件描述符状态。重点不是“看全”,而是“看准”:
- 查指定进程打开的 fd 数量:`sudo lsof -p $(pgrep nginx | head -1) | wc -l`,对比 ulimit -n 值,若接近或超过即存在风险
- 过滤普通日志文件(REG 类型):`sudo lsof -p $(pgrep nginx) | grep REG | grep log`,确认 access.log、error.log 是否被重复打开或残留旧句柄
- 识别已删除但仍在占用空间的日志:`sudo lsof +L1 | grep nginx`,输出中带 (deleted) 的行说明日志轮转后未 reload,fd 未释放
- 观察 fd 编号是否持续增长:多次执行 `sudo lsof -p $(pgrep nginx) | grep REG | wc -l`,间隔 30 秒比对数值变化,稳定则无泄漏,单边上涨需警惕
fuser:快速判断端口/文件是否被 Nginx 占用
它不展示 fd 细节,但响应极快,适合初筛和批量验证:
- 检查 80/443 端口是否由 Nginx 持有:`sudo fuser 80/tcp 443/tcp 2>/dev/null`,输出 PID 即可确认归属
- 验证某个日志路径是否正被使用:`sudo fuser /var/log/nginx/access.log 2>/dev/null`,有输出说明仍有 worker 持有该文件句柄
- 配合 -k 强制终止(慎用):`sudo fuser -k /var/log/nginx/access.log` 可临时释放句柄,但会中断写入,仅用于紧急诊断,不可替代 reload
ss:聚焦网络连接引发的 fd 泄漏
很多 fd 泄漏实际源于长连接管理异常,比如 keepalive 超时配置不合理、客户端异常断连未清理等。ss 比 netstat 更轻量、更实时:
- 统计 Nginx 相关连接总数及状态分布:`sudo ss -tanop | grep nginx | awk '{print $1}' | sort | uniq -c`
- 查看大量 TIME-WAIT 或 CLOSE-WAIT 连接:`sudo ss -tan state time-wait | grep nginx | wc -l`,若远超预期(如 >500),可能因连接未及时回收导致 fd 累积
- 结合 lsof 查看对应 fd:从 ss 输出中取一个可疑 socket 的 inode(如 ino:12345678),再执行 `sudo lsof -n | awk '$9 ~ /12345678/ {print}'`,定位到具体 fd 编号和使用场景
gdb:在不重启前提下修复特定 fd 占用(高级应急)
当确认某 worker 进程卡住一个已删除日志或异常 socket,且无法优雅 reload 时,可用 gdb 注入系统调用强行关闭。这属于非常规操作,仅限生产紧急止血:
- 先用 lsof 找出目标 fd 编号(如 6)和对应 worker PID(如 12345)
- 执行注入命令:sudo gdb -p 12345 -ex "call close(6)" -ex detach
- 验证是否成功:再次运行 `sudo lsof -p 12345 | grep 6`,应无输出;同时检查 `sudo lsof +L1 | grep nginx` 是否减少
- 注意:该操作不修改进程逻辑,只释放内核句柄;必须确保目标 fd 确实无业务依赖,否则可能引发写失败或连接中断


















