inotify简介并解决“inotify 监控达到上限!” 错误
1. 简介
现代软件通常会根据数据变化自动更新视图:
这种便利是由不同的系统提供的。
在本教程中,我们将讨论inotify系统及其功能。之后,我们探索检查其当前用户的方法。最后,我们讨论一些与inotify相关的常见错误。
我们使用 GNU Bash 5.1.4 在 Debian 11 (Bullseye) 上测试了本教程中的代码。它是 POSIX 兼容的,应该可以在任何这样的环境中工作。
2. 文件系统事件通知
我们已经将索引节点 作为本地 Linux 文件系统中的一个键进行了讨论。事实上,它们的变化与许多文件事件有关。
基于此,inotify 子系统的主要功能是监视和报告文件系统中的事件。无论是借助inotifywait 和inotifywatch 工具,还是其他软件的syscall ,我们都可以轻松掌握文件操作。
例如,我们可以使用命令行来简单地等待给定文件上的任何事件:
$ inotifywait /file.ext && echo 'Event.'
Setting up watches.
Watches established.
因此,如果*/file.ext*现在是任何操作的一部分,我们将收到通知。但是,如果我们想一次永久地对许多对象执行此操作怎么办?
3. 监控多个文件和目录树
有时我们需要更全面的监控。一种方法是将*–recursive* ( -r ) 和*–monitor* ( -m ) 开关添加到inotifywait。它们分别确保目录树处理和持续监控。
此外,我们可以使用inotifywatch来监听与文件系统的给定部分链接的事件:
$ inotifywatch /
Establishing watches...
Finished establishing watches, now collecting statistics.
由于每个文件系统对象都需要一个单独的 watch,因此 Linux 对其最大数量有一个上限。事实上,我们可以检查给定系统中的内容:
$ cat /proc/sys/fs/inotify/max_user_watches
524288
在这里,系统允许524288 (2^19)个监控 。方便的是,我们可以随时看到谁在使用它们。
4. 检查inotify用户
通过组合几个 Linux 命令,我们可以找出当前使用 watches 的进程:
$ inotifywatch / &
Establishing watches...
Finished establishing watches, now collecting statistics.
[1] 666
$ find /proc/*/fd -lname anon_inode:inotify |
cut -d/ -f3 |
xargs -I '{}' -- ps --no-headers -o '%p %U %c' -p '{}' |
uniq -c |
sort -nr
1 6660 root inotifywatch
** inotify文件描述符的数量与 watches 的数量不同**。因此,有一个脚本 ,其中包含上述命令行的更好版本以及其他功能。
此外,我们可以使用strace (系统跟踪)来获取所有监控的列表:
$ strace --follow-forks --trace='inotify_add_watch' inotifywait --quiet /file.ext
inotify_add_watch(3, "/file.ext",
IN_ACCESS|IN_MODIFY|IN_ATTRIB|IN_CLOSE_WRITE|IN_CLOSE_NOWRITE|IN_OPEN|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF) = 1
最后,还有lsof (List Open Files)工具,它也列出了inotify用户:
$ tail -f /file.ext &
[1] 666
$ lsof | grep inotify
tail 666 root 4r a_inode 0,11 0 15387 inotify
即使有各种使用和处理监控的方法,问题也并不少见。
5. 常见的inotify错误
使用inotify子系统时有一些陷阱。让我们讨论其中的一些。
5.1. 权限
事实上,与其他文件系统操作一样,我们至少需要对目标对象有一些控制。换句话说,我们无法在没有适当权限的情况下进行监控:
$ inotifywatch /root
Establishing watches...
Failed to watch /root: Permission denied
要解决这个问题,我们至少需要能够读取目标对象。在这里,我们通过chmod (更改模式)添加必要的权限:
$ chmod +r /root
完成这些更改后,我们可以添加监控。
5.2. inotify监视限制
考虑到 / 上的递归inotifywatch会占用与文件一样多的监控。事实上,在文件数量超过监视限制的文件系统上执行此操作会产生错误:
$ cat /proc/sys/fs/inotify/max_user_watches
524288<
$ df --inodes /
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdb 16777216 666000 16111216 4% /
$ inotifywatch --recursive /
Establishing watches...
Failed to watch /; upper limit on inotify watches reached!
Please increase the amount of inotify watches allowed per user via '/proc/sys/fs/inotify/max_user_watches'.
当然,解决方案在错误文本中。但是,应用它的方法不止一种:
$ max_user_watches=CUSTOM_MAX_USER_WATCHES_VALUE
$ sysctl fs.inotify.max_user_watches=${max_user_watches}
$ echo fs.inotify.max_user_watches=${max_user_watches} >> /etc/sysctl.conf
$ sysctl --load
虽然第一个命令在每个会话中应用它,但第二个命令在重启后仍然存在。那是因为它向*/etc/sysctl.conf*添加了一行。但是,如果该行已经存在,我们应该根据需要对其进行更改。我们可以避免使用最后一个命令重新启动,该命令重新读取并应用配置文件。
5.3. 主内存 (RAM) 问题
因为每个 watch 都是一个结构体,*可用内存也是使用inotify 的瓶颈。事实上,一个监控最多可以占用 1KB 的空间。这意味着一百万个监控可能会导致 1GB 的额外 RAM 使用量。 有时,这会导致奇怪的错误:
- inotify_add_watch 失败:设备上没有剩余空间 (/file.ext)
- 无法监控*“/file.ext”*:设备上没有剩余空间
释放内存似乎是可行的方法。但是,这种方法有几个问题。
首先,** inotify使用无法交换的内核内存 **。其次,即使监控刚用完,程序也可能会抛出此类错误。