Watch at Ease看见世界,读懂生活。

科技 · 实用指南

Node.js EMFILE:提高 ulimit 前先找出文件描述符限制的所有者

保存失败进程、继承的限制和描述符增长曲线,再区分低上限、泄漏、并发峰值与监视器压力。

原创编辑示意图:比较 shell、服务、进程与实时使用证据。
原创编辑示意图:修改限制前先找出描述符边界的所有者。 Watch at Ease

EMFILE 首先是所有权问题,其次才是调参问题。交互 shell、systemd 服务和重启后的进程可能拥有不同证据;重启前先保存失败 PID。

重启前固定失败进程

记录准确命令或服务、父启动器、PID、时间戳和第一条 EMFILE 堆栈。不要先重启或重装依赖;它们会清空描述符表,掩盖计数是稳定、持续增长还是短时尖峰。

读取进程真正继承的限制

在 Linux 上读取 /proc/PID/limits 的 Max open files,并与交互 shell 的 ulimit -Sn 和 -Hn 比较。子进程继承父进程限制;systemd 已启动服务后再改 shell,不会追溯改变服务。

测量当前描述符与增长

统计 /proc/PID/fd 并多次采样,把目标分为普通文件、套接字、管道和匿名描述符。计数稳定贴近上限支持限制分支;持续上升支持泄漏;并行工作时短时尖峰支持并发分支。

把监视器压力与普通文件分开

以 fs.watch 或 FSEvent 结尾的堆栈只说明监视器表面,并不证明有通用修复。比较监视范围、忽略目录和进程描述符计数;Linux 上还要区分进程描述符与独立 inotify 记账。

只修改正确的所有者

若服务继承了不必要的低软限制,在其启动器或单元中修改并重启该服务。若计数只升不降,关闭泄漏的文件、套接字或监视器;若是峰值,限制并发并及时关闭。不要改无关 shell 后宣称修复。

在原启动器下证明完成

从相同 shell、主管理器、CI 或服务单元重跑相同负载,保存新 PID 的限制、峰值和工作后基线。完成意味着不再出现 EMFILE 且计数回到可解释稳态,而不只是重启后偶然通过。

原创编辑示意图:区分低上限、泄漏、并发峰值和监视器压力。
原创编辑示意图:一次描述符快照区分四种不同修复。 Watch at Ease