直接看 /proc/sys/fs/file-nr 第二列即当前系统真实活跃占用的文件描述符数;该值不依赖权限、不受 lsof 干扰,是监控告警的核心指标,现代内核中若长期大于1000则可能存在泄漏。

直接看 /proc/sys/fs/file-nr 的第二列,就是当前系统真实活跃占用的文件描述符数——不是估算,不依赖权限,也不受 lsof 自身开销干扰。
为什么不能用 lsof | wc -l 统计系统总量
一旦权限不够,lsof 的输出就会被直接打断,root 或其他用户的进程很容易被漏统计;再加上它会把已经关闭但还没来得及回收的 socket、重复记录、表头甚至空行都算进去,最终结果往往会被抬高 20%~50%。更棘手的是,lsof 运行时自己还得先打开一批 fd,这样一来,不仅影响统计准确性,连资源消耗也会在统计过程中被进一步放大。
- 真正可靠的系统级总数:执行
cat /proc/sys/fs/file-nr,输出形如12480 3210 2097152 - 第一列是“已分配总数”,第三列等于
fs.file-max,第二列才是“当前活跃占用” - 现代内核中第二列长期为 0 是正常现象,此时实际用量 ≈ 第一列
- 如果第二列持续 >1000,说明内核句柄回收延迟或存在泄漏,得进一步查
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 - 验证限制是否生效:
cat /proc/1234/limits | grep "Max open files",确认 Soft 和 Hard Limit 值
systemd 服务的 fd 限制为什么总是不生效
改了 /etc/security/limits.conf 或执行了 ulimit -n,对 systemd 启动的服务完全没用——它压根不读这些配置。
- 必须编辑对应 service 文件,例如
/etc/systemd/system/nginx.service - 在
[Service]段下添加LimitNOFILE=65535(不是nofile,也不是NOFILE) - 写错位置(比如放在
[Unit]下)或漏掉sudo systemctl daemon-reload都会导致无效 - 容器场景要额外加
--ulimit nofile=65536:65536,Docker 默认不继承宿主机 ulimit
真正最容易被忽视的,其实是 /proc/sys/fs/file-nr 的第二列:如果它长期不为零,症结往往不在配置给得够不够大,而在于句柄没有被及时 close。麻烦就在这里,这类泄漏通常不会马上报错,表面上看系统也还能撑住,可一旦碰上并发高峰,Too many open files 往往就会突然集中爆发。