系统级文件描述符上限应直接读取/proc/sys/fs/file-max,该值为内核实时运行值,最权威;/proc/sys/fs/file-nr第二列反映已分配未释放fd数,现代内核常为0,实际已用量≈第一列;ulimit -n仅限当前shell,systemd服务需验证/proc/[pid]/limits中soft/hard limit是否生效。

查系统级上限:直接读 /proc/sys/fs/file-max
这是最权威、最实时的系统总文件描述符上限值,不依赖缓存或配置文件。执行 cat /proc/sys/fs/file-max 得到的数字,就是内核当前允许分配的 FD 总数。别信 sysctl fs.file-max 的输出——某些发行版(如 RHEL 8+)用 systemd-sysctl 管理,sysctl 显示的是缓存值,而 /proc/sys/fs/file-max 是真实运行时值。
查当前已用数量:盯紧 /proc/sys/fs/file-nr 的第二列
cat /proc/sys/fs/file-nr 输出三列,例如 12480 3210 2097152。第一列是“已分配总数”,第三列等于 file-max,但真正反映“当前活跃占用”的是第二列(已分配但未释放的 FD 数)。现代内核中这一列基本恒为 0,所以实际已用量 ≈ 第一列。但注意:如果第二列长期非零(比如 >1000),说明内核句柄回收有延迟或泄漏,需进一步排查。
- 别用
lsof | wc -l:权限不足会中断统计,且包含无效条目(如已关闭的 socket) - 也别只看单个进程的
/proc/[pid]/fd/:局部高 ≠ 全局瓶颈 - 快速预警脚本:
awk '{printf "Used: %d/%d (%.1f%)\n", $1, $3, $1/$3*100}' /proc/sys/fs/file-nr
查用户/进程级限制:ulimit -n 不等于真实可用
ulimit -n 只显示当前 shell 的软限制,对 systemd 启动的服务完全无效。Nginx、Redis、Java 进程哪怕你改了 /etc/security/limits.conf,只要没在对应 .service 文件里写 LimitNOFILE=65535,就还是继承默认的 1024 或 4096。验证方式必须是:cat /proc/$(pgrep nginx | head -n1)/limits | grep "Max open files",看输出里的 Soft 和 Hard Limit 是否真变了。
为什么改了所有参数还是报错
常见漏掉的三个卡口:
-
fs.nr_open:单进程硬上限,默认 1048576。如果你把fs.file-max设成 2097152,但fs.nr_open没同步调高,新进程仍被截断 -
LimitNOFILE在 systemd service 文件里写错位置:必须放在[Service]段下,写在[Unit]或[Install]下无效 - 容器场景:Docker 默认不继承宿主机
ulimit,必须显式加--ulimit nofile=65536:65536
真正关键的不是“设多大”,而是确认每层限制都落到具体进程的 /proc/[pid]/limits 里——那里才是最终生效的地方。











