华为云ECS文件描述符耗尽排查:从EMFILE到LimitNOFILE

举报
yd_252351073 发表于 2026/11/09 17:12:29 2026/11/09
【摘要】 在华为云 ECS 上跑 Web、代理或长连接服务时,日志里突然出现 `Too many open files`,进程拒绝 accept、open 或建立新连接,需要先区分资源限制的层级,而不是直接把 `ulimit -n` 或 `fs.file-max` 调大。两类需要区分的原因是**单进程**的 `RLIMIT_NOFILE`(errno `EMFILE`)与系统级文件表上限(errno `EN

在华为云 ECS 上跑 Web、代理或长连接服务时,日志里突然出现 Too many open files,进程拒绝 accept、open 或建立新连接,需要先区分资源限制的层级,而不是直接把 ulimit -n 或 fs.file-max 调大。两类需要区分的原因是单进程的 RLIMIT_NOFILE(errno EMFILE)与系统级文件表上限(errno ENFILE)。更稳妥的做法是:先只读取证,分清是谁的上限,再决定是否改配置;抬上限解决不了文件描述符泄漏。

一、先分清 EMFILE 与 ENFILE

内核与手册对两类错误的含义区分很清楚:

  • EMFILE:当前进程已达到自身的打开文件数上限,对应资源限制 RLIMIT_NOFILE(软限制为内核实际强制值)。
  • ENFILE:整机打开文件(open file descriptions)数量触及系统上限,通常与 fs.file-max 相关。

同一句“Too many open files”在应用日志里可能被笼统写出,因此要以出错进程的 errno、内核日志线索、以及 /proc 上的用量与上限来定性。把系统级参数调高,对已经撞上进程软限制的服务往往无效;反过来,只抬进程上限,也解决不了真正的系统级耗尽。

补充一点语义:手册对 RLIMIT_NOFILE 的表述是“可打开的最大文件描述符编号再加一”。实务排查里,仍把 soft 当作该进程允许同时打开的描述符数量上限来对照即可,但写自动化告警时不要把它和“已打开个数”混用同一字段名而不加注释。

二、只读取证:limits 与 fd 目录

锁定可疑 PID 后,优先做只读对照,再谈改配置。

查看该进程当前的软/硬限制:

rg "Max open files" /proc/PID/limits

左侧为 soft,中间为 hard。软限制是内核强制执行的上限;硬限制是软限制的天花板。无特权进程只能把软限制调到不超过硬限制,不能擅自抬高硬限制。

估算当前打开数量(把 PID 换成实际进程号):

ls /proc/PID/fd | wc -l

注意三点:

  1. 权限:读取 /proc/PID/limits 在较新内核上通常对所有用户可读;但枚举或解析 /proc/PID/fd 下符号链接可能受 ptrace 访问模式约束,非属主、无足够权限时会失败或信息不完整。
  2. 采样竞态:fd 在不断 open/close,目录列举与计数之间可能有短暂偏差,应多次采样并与峰值、错误时刻对照。
  3. 对照关系:若 fd 计数已逼近 soft,而系统级用量仍远离上限,优先按 EMFILE / 进程侧处理。

日志侧可再确认是否出现系统级耗尽相关内核提示(例如文件句柄上限触达的 VFS 类消息)。有则再查系统级参数;没有,则不要先改 fs.file-max。

三、系统级:file-nr、file-max 与 nr_open

系统级只读入口:

rg . /proc/sys/fs/file-nr
rg . /proc/sys/fs/file-max
rg . /proc/sys/fs/nr_open

file-nr 一般有三列:已分配句柄数、空闲句柄数、最大值。自 Linux 2.6 起,第二列(空闲)在现代内核上通常恒为 0,这不代表异常,只表示已分配与正在使用匹配;不要把“第二列是 0”误判成“没有空闲、马上要爆”。判断是否接近系统上限,应看第一列是否逼近第三列(亦即 file-max)。

fs.nr_open 是进程可将 RLIMIT_NOFILE 硬限制抬到的天花板;默认常见为 1048576。试图把硬限制抬到超过 nr_open 会失败。只有在确认需要超高单进程硬限制时,才考虑动它;日常 EMFILE 排查里,更常是 soft 卡在 1024 一类默认值。

sysctl 查看同名项即可。任何写入示例都必须按本机容量、进程数与业务峰值估算,没有放之四海的“推荐值”。

四、别被 shell 的 ulimit 误导

交互 shell 里的 ulimit -n 只反映当前 shell 会话及其随后拉起的子进程继承关系,不会改写已经在跑的守护进程,也不会自动改写 systemd 管理的服务单元。

对 systemd 服务,应同时看单元配置与真实进程:

systemctl show your-service.service -p LimitNOFILE -p LimitNOFILESoft -p MainPID
rg "Max open files" /proc/主进程PID/limits

LimitNOFILE / LimitNOFILESoft 是单元侧配置(及规范化后的硬/软值);/proc/PID/limits 才是该进程此刻真正生效的限制。若服务启动后自行抬高了软限制,或以非 systemd 方式启动,两边可能不一致——以进程侧为准。

systemd 常见默认是软限制 1024、硬限制较高(许多发行版上硬限制为 524288 量级)。软限制长期保持 1024,重要原因之一是:Linux 上 select 无法可靠处理编号大于等于 1024 的描述符;盲目全局抬高软限制,可能让仍依赖 select 的旧代码异常。能使用 poll/epoll 且明确不依赖 select 的服务,才适合把软限制抬向硬限制。

五、若必须调整:维护窗口内的示例,而非万能处方

确认是进程软限制过紧、且业务确需更高并发描述符后,再在计划内重启/重载维护窗口用 systemd drop-in 调整。下面数值仅为容量规划示例,须按连接数、每个连接占用的描述符(例如反向代理常见“客户端 + 上游”成对占用)、工作进程数自行核算,不是通用推荐值:

# systemctl edit your-service.service 生成的覆盖示例
[Service]
LimitNOFILE=65535:262144

软:硬 格式分别设置 soft 与 hard。也可写成单一数值使软硬相同。改完后需按该服务文档执行 daemon-reload 并在维护窗口重启服务,新限制才作用于新进程;对已运行进程,仅改单元不会自动生效。

涉及 fs.file-max / fs.nr_open 的 sysctl 示例同样必须基于观测到的 file-nr 与容量余量来写,并持久化到发行版惯用的 sysctl 配置中;此处不给出伪“标准值”,避免被当成万能处方复制。

六、先查泄漏与连接池,而不是只会抬上限

抬高 LimitNOFILE 只能推迟症状。若 fd 计数在稳定流量下持续爬升且从不回落,更像泄漏或池化不当:

  • 未关闭的临时文件、管道、eventfd、inotify 等;
  • HTTP/数据库/缓存客户端连接池上限过大或空闲连接未回收;
  • 反向代理每个工作进程的客户端连接与上游连接总量超出容量预算;
  • fork 出的子进程继承并长期占用父进程打开的描述符。

在 /proc/PID/fd 可抽样看指向 socket:、普通文件还是匿名 inode;结合应用指标(池大小、活跃连接数、主动关闭策略)定位。TIME_WAIT 通常已不占用用户进程的文件描述符,不能把它的数量直接当作进程 fd 数。权限不足时,改用有权限的运维账号或在维护窗口用服务同用户身份观测。修复泄漏或收缩池之后,再评估是否仍需更高上限。

若短时突发流量导致触及 soft、而常规定时采样看不到峰值,可在复现窗口提高采样频率,或在应用侧临时打开更细的连接/池指标;不要仅凭一次 ls | wc 否定上限问题,也不要在未确认泄漏前把 hard/soft 一次拉到接近 nr_open。

方法说明

本文依据公开的 Linux 手册页与 systemd 文档整理排查方法论,未在真实华为云 ECS 实例上执行命令,也不声称任何实测数据或压测结果。请在你自己的环境用只读命令复核后再做变更;配置数值须按业务容量单独核算。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。