适用于 Linux 5.4+、systemd 245+。示例单元要替换;读取其他用户进程的 /proc 和 socket 归属通常需要 root 或相应权限。先保留报错原文:EMFILE 是进程自己的描述符用完,ENFILE 才是系统文件表耗尽,两者处理方向不一样。
unit=app.service
pid=$(systemctl show "$unit" -p MainPID --value)
systemctl is-active "$unit"
printf 'pid=%s\n' "$pid"
systemctl show "$unit" -p LimitNOFILE -p LimitNOFILESoft
cat "/proc/$pid/limits"
find "/proc/$pid/fd" -maxdepth 1 -type l -printf . 2>/dev/null | wc -c
cat /proc/sys/fs/file-nr
cat /proc/sys/fs/file-max
MainPID=0 时服务当前没有主进程,别继续读 /proc/0。LimitNOFILESoft 和 /proc/$pid/limits 里的 soft limit 更接近进程实际撞到的门槛;file-nr 的三列分别是已分配、已分配但未使用、系统上限,第三列也应和 file-max 对照。
数量接近 soft limit 时,再看主要是哪类描述符。下面按目标做一个粗分组;网络和 Unix socket 的进程信息可能仍需更高权限:
for fd in /proc/$pid/fd/*; do readlink "$fd"; done 2>/dev/null \
| sed -E 's/^socket:\[[0-9]+\]$/socket/; s/^pipe:\[[0-9]+\]$/pipe/; s/^anon_inode:.*$/anon_inode/' \
| sort | uniq -c | sort -nr | head -n 20
ss -tanp
ss -xap
socket 持续增加时查连接生命周期和超时,普通文件增加时查未关闭的文件、日志或临时文件,anon_inode 增加则继续定位 epoll、eventfd 等对象。不要只把 LimitNOFILE 调大就结束:修复后应在相同流量窗口连续采样,确认描述符数量会回落或稳定在 soft limit 以下,日志不再出现 EMFILE/ENFILE,并用真实业务请求验证服务正常。