在 Linux 系统中,直接查看 /proc/sys/fs/file-nr 的第二列,就能判断当前系统真实活跃占用的文件描述符数量;这个数值不依赖权限、不受 lsof 统计误差影响,是进行文件描述符监控与告警时最关键的参考指标。对于现代内核来说,如果该值长期大于 1000,通常意味着可能存在文件描述符泄漏或内核回收延迟问题。

最直接、最准确的方式,就是查看 /proc/sys/fs/file-nr 的第二列,它表示当前系统真实正在活跃占用的文件描述符数量——不是粗略估算,不依赖用户权限,也不会受到 lsof 本身开销和统计方式的干扰。
为什么不能用 lsof | wc -l 统计系统总量
很多人在 Linux 中查看文件描述符占用时,会习惯使用 lsof | wc -l,但这种方法并不适合统计系统级总量。只要权限不足,lsof 输出就可能被中断,导致 root 或其他用户进程未被完整统计;此外,它还可能把已经关闭但尚未回收的 socket、重复记录、表头甚至空行一并算进去,结果往往偏高 20%~50%。更麻烦的是,lsof 在执行过程中自身也会打开一批 fd,这不仅影响统计准确性,还会额外增加资源消耗。
- 真正可靠的系统级文件描述符总量查看方式:执行
cat /proc/sys/fs/file-nr,输出示例为12480 3210 2097152 - 第一列表示“已分配总数”,第三列对应
fs.file-max,而第二列才是“当前活跃占用数” - 在现代 Linux 内核中,第二列长期为 0 属于正常情况,这时实际文件描述符使用量通常可近似看作第一列
- 如果第二列持续 >1000,往往说明内核句柄回收存在延迟,或系统中可能有 fd 泄漏,需要继续用
lsof -n | awk '{print $2}' | sort | uniq -c | sort -nr | head -10排查高占用进程
怎么查单个进程的 fd 实际打开数
如果你想查看某个进程实际打开了多少文件描述符,最准确、最轻量的方式是检查 /proc/[pid]/fd/ 目录。这个目录由内核实时维护,里面的每个数字项都对应一个当前已打开的 fd,因此直接计数最可靠。
- 先获取进程 PID:例如使用
pgrep nginx或pidof redis-server - 统计文件描述符数量:
ls /proc/1234/fd/ | wc -w(注意不要使用ls -l再配合wc -l,否则会因为多出总计行而误算) - 排除非数字项(如
stdin、cwd):ls /proc/1234/fd/ | grep -E '^[0-9]+$' | wc -w - 验证进程 fd 限制是否生效:
cat /proc/1234/limits | grep "Max open files",检查 Soft Limit 与 Hard Limit 是否符合预期
systemd 服务的 fd 限制为什么总是不生效
很多人修改了 /etc/security/limits.conf,或者手动执行 ulimit -n,却发现对 systemd 启动的服务没有效果。这是因为 systemd 管理的服务不会读取这些配置,所以即使修改正确,也不会自动生效。
- 必须编辑对应的 service 配置文件,例如
/etc/systemd/system/nginx.service - 在
[Service]段中添加LimitNOFILE=65535(注意不是nofile,也不是NOFILE) - 如果写错位置(例如放到
[Unit]下)或忘记执行sudo systemctl daemon-reload,配置都会失效 - 在容器环境中还需要额外设置
--ulimit nofile=65536:65536,因为 Docker 默认不会继承宿主机的 ulimit 设置
实际排查 Linux 文件描述符占用问题时,最容易被忽略但最值得重点关注的,就是 /proc/sys/fs/file-nr 的第二列。如果它长期不为 0,问题往往不在于 fd 限制设置得够不够大,而在于文件句柄没有被及时 close。难点也正是在这里:这类文件描述符泄漏通常不会立刻报错,表面上系统似乎还能正常运行,但一旦遇到高并发流量或业务峰值,Too many open files 错误就可能集中爆发。
