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

科技 · 实用指南

Linux 提示“inotify 监视数量达到上限”?调大 sysctl 前先证明进程和限制

inotify 返回 ENOSPC,可能是单用户实例耗尽、监视项耗尽,也可能另有事件队列溢出。先把活动描述符和监视对象归属到真实进程,再缩小范围,或只提高已证实的边界。

区分 inotify 实例、监视项与队列限制的示意图
原创插画:修改 sysctl 前先区分真正耗尽的 inotify 边界。 Watch at Ease

inotify 返回 ENOSPC,可能是单用户实例耗尽、监视项耗尽,也可能另有事件队列溢出。先把活动描述符和监视对象归属到真实进程,再缩小范围,或只提高已证实的边界。

max_user_instances 与 max_user_watches 都按真实用户 ID 计账。 max_queued_events 限制新建 inotify 实例可排队的事件数。

1. 冻结调用者和计账身份

在重启前记录完整 ENOSPC 文本、程序、PID、有效与真实 UID、容器或服务边界、监视根目录和首个时间戳,并读取真正持有内核对象的主机上三个 fs.inotify 参数的当前值。

不要因 errno 名称就假设磁盘空间不足,也不要先粘贴网上常见的 sysctl 数值。这三个控制项回答不同问题,同一真实 UID 下的多个进程还会共享单用户配额。

2. 区分实例、监视项与队列边界

创建 inotify 实例时失败更接近实例上限;添加 watch 时失败更接近监视项上限,但库可能隐藏具体系统调用,所以必须保留原始调用路径。

队列溢出是另一类故障:实例已存在,消费者读取速度跟不上,内核会报告 IN_Q_OVERFLOW。增加 max_user_watches 无法找回已丢事件,应用必须重新扫描或重建视图。

3. 通过 fdinfo 归属实时消耗

按 PID 和真实 UID 枚举 inotify 文件描述符,再查看 /proc/<pid>/fdinfo/<fd>。统计其中的 inotify 行估算每个描述符和进程的 watch 数,只保留 wd、inode、device、mask 的少量样本,避免把敏感路径树贴进公开工单。

把最大消耗进程与预期监视根比较。递归工具可能确实需要大量 watch,但重复依赖树、生成目录、绑定挂载或重启循环会放大数量。容器场景通常还要回到主机侧映射真实 UID。

4. 带回滚地修复最窄原因

优先删除重复根目录,在工具支持时排除生成目录或依赖目录,并修复泄漏实例的重启或初始化循环。保留证据后只重启已识别进程;整机重启会抹掉归属线索,常常只是暂时缓解。

若测得的合法稳态需求确实超过已证实上限,只通过系统管理的 sysctl 机制修改该一项。保存旧值、理由、预期峰值和回滚触发条件;不要同时提高三个参数,也不要宣称存在通用安全值。

5. 重启后验证监视数量和事件交付

启动一个受控工作负载,记录该真实 UID 与 PID 新产生的实例数和 watch 数,确认数量在预期范围稳定,而不是每次构建或重连后持续增长。

在监视根内创建、修改、重命名并删除代表性文件,确认应用收到依赖的全部事件类型、没有 IN_Q_OVERFLOW,且其他用户仍有余量。若数量或漏事件违反验收门槛,就回滚更改。

inotify 归属、修复与事件验收示意图
原创插画:先归属所有者,只做一项有界更改,再证明事件交付。 Watch at Ease