Linux服务器出现Too many open files怎么办?文件描述符排查与限制调整教程

Linux服务器出现Too many open files怎么办?文件描述符排查与限制调整教程

Linux 服务报出 Too many open files 时,磁盘通常没有问题。它表示某个进程或整个系统已经无法继续分配文件描述符。网站可能随之出现连接失败、接口超时、Nginx 502、数据库连接异常,日志中也可能看到 EMFILEENFILE

文件描述符不只对应普通文件。网络套接字、管道、日志文件、设备和监听端口都会占用描述符。因此,排查时不能只盯着“打开了多少日志”,还要检查连接数量、程序是否泄漏,以及限制究竟来自哪一层。

一、先判断是哪个服务触发了限制

先查看故障时间附近的系统日志。下面以 Nginx 为例:

journalctl -u nginx --since "30 minutes ago" --no-pager

也可以在系统日志中搜索相关报错:

journalctl --since "30 minutes ago" --no-pager | grep -Ei "too many open files|EMFILE|ENFILE"

常见含义如下:

  • EMFILE:当前进程达到自己的文件描述符上限。
  • ENFILE:系统级打开文件表接近或达到上限。

大多数线上故障属于前一种。确认服务名后,先取得主进程 PID:

systemctl show nginx -p MainPID --value

如果输出为 0,说明服务当前未运行,或者该单元没有可用的主进程。此时可结合 systemctl status nginx 和应用自身日志继续确认。

二、查看进程已经使用多少文件描述符

假设进程 PID 为 1234,可以统计 /proc 中的描述符数量:

find /proc/1234/fd -maxdepth 1 -type l 2>/dev/null | wc -l

再查看这个进程的软限制和硬限制:

grep "Max open files" /proc/1234/limits

输出通常包含 Soft Limit 和 Hard Limit。进程实际运行时不能超过软限制;软限制又不能高于硬限制。

还可以用 lsof 查看描述符主要被什么占用:

lsof -nP -p 1234

只想看数量时,可使用:

lsof -nP -p 1234 2>/dev/null | wc -l

lsof 的输出包含表头,而且进程状态可能在统计期间变化,因此数量可能与 /proc/1234/fd 略有差异。排障时看趋势和占用类型即可,不必要求两个数字完全一致。

三、找出占用文件描述符最多的进程

不知道具体是哪个服务时,可以按进程统计 /proc/*/fd。下面的命令只读取当前用户有权限访问的进程:

for p in /proc/[0-9]*; do
  n=$(find "$p/fd" -maxdepth 1 -type l 2>/dev/null | wc -l)
  name=$(cat "$p/comm" 2>/dev/null)
  printf "%8s  %-8s  %s\n" "$n" "${p##*/}" "$name"
done | sort -nr | head -20

第一列是描述符数量,第二列是 PID,第三列是进程名。执行期间进程可能退出,少量读取失败属于正常情况。

如果某个进程的描述符数量持续上涨,长时间不回落,需要继续判断它是在承载正常高并发,还是存在连接、文件或管道未释放的问题。

四、检查描述符都用在了哪里

查看某个进程中最常见的描述符类型:

lsof -nP -p 1234 | awk 'NR>1 {print $5}' | sort | uniq -c | sort -nr

常见类型包括:

  • REG:普通文件,可能是日志、缓存或业务数据文件。
  • IPv4IPv6:网络连接和监听套接字。
  • FIFO:命名管道或进程间通信。
  • CHR:字符设备。

如果网络套接字占比很高,可进一步查看连接状态:

ss -s
ss -antp | head -100

大量 CLOSE-WAIT 往往说明应用没有及时关闭对端已经断开的连接;大量长时间存在的空闲连接,则要检查连接池、Keep-Alive、上游超时和客户端行为。

如果普通文件占比异常,可以列出打开次数较多的路径:

lsof -nP -p 1234 | awk 'NR>1 && $5=="REG" {print $9}' | sort | uniq -c | sort -nr | head -30

文件名包含空格时,这个统计命令只适合快速观察。需要精确分析时,应直接查看完整的 lsof 输出或使用程序自身的诊断工具。

五、systemd服务应该怎样调整限制

现在多数 Linux 服务器通过 systemd 管理 Nginx、Docker、Redis、Java 和自建服务。先查看服务当前的限制:

systemctl show nginx -p LimitNOFILE

如果确认业务并发量确实需要更高限制,可创建覆盖配置:

sudo systemctl edit nginx

写入:

[Service]
LimitNOFILE=65535

保存后重新加载 systemd 配置,并在合适的维护时间重启服务:

sudo systemctl daemon-reload
sudo systemctl restart nginx

重启会中断现有连接。生产环境应先检查配置、确认负载均衡或备用节点可用,再安排滚动重启。

重启后重新取得 PID,并验证实际限制:

pid=$(systemctl show nginx -p MainPID --value)
grep "Max open files" "/proc/$pid/limits"

不要直接修改软件包自带的 unit 文件。升级软件时,这类改动可能被覆盖;systemctl edit 生成的 drop-in 配置更容易维护和回滚。

六、为什么修改ulimit或limits.conf没有生效

在终端执行:

ulimit -Sn
ulimit -Hn

看到的是当前 Shell 的软限制和硬限制。使用 ulimit -n 65535 修改后,只会影响当前 Shell 以及从它启动的子进程,不会自动改变已经运行的服务。

/etc/security/limits.conf/etc/security/limits.d/*.conf 主要通过 PAM 影响登录会话。例如:

www-data soft nofile 65535
www-data hard nofile 65535

这类配置通常不直接控制 systemd 系统服务。由 systemd 启动的服务应优先使用 LimitNOFILE=,并以 /proc/PID/limits 的实际结果为准。

七、检查系统级文件表是否接近上限

查看系统级限制:

sysctl fs.file-max
cat /proc/sys/fs/file-nr

fs.file-max 是系统可分配文件句柄的上限。file-nr 用于观察系统当前文件句柄的分配情况;不同内核版本的统计细节可能不同,判断时应结合当前内核文档和持续监控数据。

如果日志明确出现系统级文件表耗尽,并且确认不是单个应用泄漏,可以临时调整:

sudo sysctl -w fs.file-max=2097152

需要长期生效时,在 /etc/sysctl.d/ 中建立单独配置,例如:

echo 'fs.file-max = 2097152' | sudo tee /etc/sysctl.d/90-file-max.conf
sudo sysctl --system

数值应根据内存、业务并发和监控结果确定。提高系统上限不会修复程序泄漏,设置过大也不能替代容量规划。

八、临时恢复服务时应该怎么做

线上服务已经无法接受新连接时,可以按下面的顺序处理:

  1. 保存故障日志、进程 PID、/proc/PID/limits、描述符数量和 lsof 结果。
  2. 确认是否存在异常连接、日志句柄、临时文件或明显泄漏。
  3. 有备用节点时先切走流量,再重启故障实例释放描述符。
  4. 根据正常峰值调整服务限制,同时修复连接或文件未关闭的问题。
  5. 增加描述符使用量监控,观察修复后是否再次持续增长。

不要在没有记录现场信息的情况下反复重启。重启会清空进程级证据,后续很难判断是限制偏低,还是应用持续泄漏。

九、建议增加哪些监控

至少记录以下指标:

  • 关键进程已打开文件描述符数量。
  • 进程 Max open files 软限制。
  • 描述符使用率,而不只是绝对数量。
  • 系统级文件句柄分配情况。
  • TCP 连接总数及 ESTABLISHEDTIME-WAITCLOSE-WAIT 状态。
  • 应用连接池、请求量和错误率。

告警阈值应留出处理时间。例如进程描述符使用率持续超过 70% 时预警,超过 85% 时提高告警级别。具体阈值还要结合业务峰值和增长速度调整。

总结

Too many open files 的排查重点是找到限制层级和描述符去向。先从报错服务定位 PID,再检查 /proc/PID/fd/proc/PID/limitslsof。systemd 服务使用 LimitNOFILE= 调整进程限制;登录会话才主要受 ulimit 和 PAM limits 配置影响。只有确认系统级文件表不足时,才考虑修改 fs.file-max

限制调高后仍需观察描述符数量是否持续增长。正常高并发需要合理容量,程序泄漏则需要修复连接、文件或管道的释放逻辑。

参考资料

知识库

MySQL发生死锁怎么办?死锁日志、事务定位与索引优化教程

2026-8-20 17:21:39

知识库

服务器被黑了吗?5个命令快速自查(附应急清单)

2026-4-10 15:11:58