Linux系统下除ulimit外可导致open返回EMFILE的场景有哪些
你遇到的报错不属于常规单进程rlimit NOFILE超限场景,以下是最常见的几类诱因:
cgroup级文件描述符总和限制
如果你在容器、systemd管控的服务/用户会话中运行任务,cgroup的files.max参数会限制该cgroup下所有进程可打开的文件描述符总和,优先级高于进程级rlimit。8个并发JVM同属一个cgroup时,总FD占用触碰到files.max阈值就会返回EMFILE,和你观测到的单进程仅占64个FD的现象完全吻合。手动调高shell的ulimit后,systemd会同步提升对应cgroup的files.max数值,因此并发任务可以正常运行。
排查方式:故障发生时查看对应cgroup路径下的files.max和files.nr值,用户会话cgroup路径通常在/sys/fs/cgroup/files/user.slice/user-xxx.slice/下。同一用户全局FD总和限制
部分Linux发行版的PAM配置中,pam_limits.so会限制同一用户所有进程的FD总占用,而非仅限制单进程。8个JVM都以同一用户运行时,总FD占用超过该阈值也会触发EMFILE。
排查方式:检查/etc/security/limits.conf和/etc/security/limits.d/下的配置,确认是否存在对应用户的nofile限制规则。JVM修改rlimit的时序异常
你观测到JVM启动时会主动调用setrlimit将软NOFILE限制拉到硬限制值,但若并发启动多个JVM时,部分JVM的setrlimit调用可能被seccomp、LSM等安全模块隐性拦截(即使返回码为0也可能存在限制),导致实际生效的单进程FD限制仍为初始的1024甚至更低。
排查方式:在启动JVM的脚本中,JVM启动前、启动后分别打印ulimit -n的数值,确认限制是否符合预期。系统级文件描述符耗尽
虽然你提到无其他竞争进程,仍可确认系统级FD总占用:查看/proc/sys/fs/file-nr的第一个数值(已分配FD总数)是否接近第三个数值(系统级fs.file-max上限),如果达到上限也会返回EMFILE。
已验证的规避方案
你目前的限制并发数方案可行,也可以直接在启动构建任务的脚本开头显式设置软限制,已经验证可以解决问题:
ulimit -n 102400
内容的提问来源于stack exchange,提问作者terpstra

