写点什么

Inotify: 高效、实时的 Linux 文件系统事件监控框架

2010 年 9 月 22 日

概要 - 为什么需要监控文件系统?

在日常工作中,人们往往需要知道在某些文件 (夹) 上都有那些变化,比如:

  • 通知配置文件的改变
  • 跟踪某些关键的系统文件的变化
  • 监控某个分区磁盘的整体使用情况
  • 系统崩溃时进行自动清理
  • 自动触发备份进程
  • 向服务器上传文件结束时发出通知

通常使用文件轮询的通知机制,但是这种机制只适用于经常改变的文件 (因为它可以确保每过 x 秒就可以得到 i/o),其他情况下都非常低效,并且有时候会丢失某些类型的变化,例如文件的修改时间没有改变。像 Tripwire 这样的数据完整性系统,它们基于时间调度来跟踪文件变化,但是如果想实时监控文件的变化的话,那么时间调度就束手无策了。Inotify 就这样应运而生了。本文将简要介绍 inotify,告诉我们如何监控文件夹,如何一有变化就报告相关消息事件,并介绍了一些相关工具, 我们可以把它们添加到自己的工具箱中。

Inotify 到底是什么?

Inotify 是一种文件变化通知机制,Linux 内核从 2.6.13 开始引入。在 BSD 和 Mac OS 系统中比较有名的是 kqueue ,它可以高效地实时跟踪 Linux 文件系统的变化。近些年来,以 fsnotify 作为后端,几乎所有的主流 Linux 发行版都支持 Inotify 机制。如何知道你的 Linux 内核是否支持 Inotify 机制呢?很简单,执行下面这条命令:

复制代码
% grep INOTIFY_USER /boot/config-$(uname -r)
CONFIG_INOTIFY_USER=y

如果输出 (‘CONFIG_INOTIFY_USER=y’),那么你可以马上享受 Inotify 之旅了。

简单的文件变化通知样例:

好的开始是成功的一半,对于了解 Inotify 机制来说,让我们从使用 inotifywait 程序开始,它包含在 inotify-tools 工具包中。假如我们打算监控 /srv/test 文件夹上的操作,只需执行:

复制代码
% inotifywait -rme modify,attrib,move,close_write,create,delete,delete_self /srv/test
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.

上述任务运行的同时,我们在另一个 shell 里依次执行以下操作:创建文件夹,然后在新文件夹下创建文件,接着删除新创建的文件:

复制代码
% mkdir /srv/test/infoq
% echo TODO > /srv/test/infoq/article.txt
% rm /srv/test/infoq/article.txt

在运行 inotifywait 的 shell 中将会打印以下信息:

复制代码
/srv/test/ CREATE,ISDIR infoq
/srv/test/infoq/ CREATE article.txt
/srv/test/infoq/ MODIFY article.txt
/srv/test/infoq/ CLOSE_WRITE,CLOSE article.txt
/srv/test/infoq/ DELETE article.txt

显而易见,只要有变化我们就会收到相关的通知。如果想了解关于 Inotify 提供的事件 (如 modify, atrrib 等) 的详细信息,请参考 inotifywatch 的 manpage。实际使用时,如果并不想监控某个大文件夹,那么就可以使用 inotifywait 的 exclude 选项。例如:我们要忽略文件夹 /srv/test/large,那么就可以这样来建立监控:

复制代码
% inotifywait --exclude '^/srv/test/(large|ignore)/' -rme modify,attrib,move,close_write,create,delete,delete_self /srv/test
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.

上面的例子中,在 exclude 选项的匹配串中我们使用了正则表达式,因为我们不想将名称中含有 large 或 ignore 的文件也排除掉。我们可以测试一下:

复制代码
% echo test > /srv/test/action.txt
% echo test > /srv/test/large/no_action.txt
% echo test > /srv/test/ignore/no_action.txt
% echo test > /srv/test/large-name-but-action.txt

这里 inotifywait 应该只会报告’action.txt’和’large-name-but-action.txt’两个文件的变化,而忽略子文件夹’large’和’ignore’下的文件,结果也确实如此;

复制代码
/srv/test/ CREATE action.txt
/srv/test/ MODIFY action.txt
/srv/test/ CLOSE_WRITE,CLOSE action.txt
/srv/test/ CREATE large-name-but-action.txt
/srv/test/ MODIFY large-name-but-action.txt
/srv/test/ CLOSE_WRITE,CLOSE large-name-but-action.txt

另外,通过使用 -t 选项我们还可以定义 inotifywait 的监控时间,既可以让它执行一段时间,也可以让它一直运行。 util-linux-ng 的 logger 命令也可以实现此功能,不过得先把相关的消息事件发送到 syslog,然后从 syslog 服务器再分析整合。

Inotifywatch - 使用 inotify 来统计文件系统访问信息

Inotify-tools 中还有一个工具叫 inotifywatch,它会先监听文件系统的消息事件,然后统计每个被监听文件或文件夹的消息事件,之后输出统计信息。比如我们想知道某个文件夹上有那些操作:

复制代码
% inotifywatch -v -e access -e modify -t 120 -r ~/InfoQ
Establishing watches...
Setting up watch(es) on /home/mika/InfoQ
OK, /home/mika/InfoQ is now being watched.
Total of 58 watches.
Finished establishing watches, now collecting statistics.
Will listen for events for 120 seconds.
total modify filename
2 2 /home/mika/InfoQ/inotify/

很显然,这里我们监控的是~/InfoQ 文件夹,并且可以看到 /home/mika/InfoQ/inotify 上发生了两个事件。方法虽简单,但却很有效。

Inotify 的配置选项

使用 Inotify 时,要特别注意内核中关于它的两个配置。首先 /proc/sys/fs/inotify/max_user_instances 规定了每个用户所能创建的 Inotify 实例的上限;其次 /proc/sys/fs/inotify/max_user_watches 规定了每个 Inotify 实例最多能关联几个监控 (watch)。你可以很容易地试验在运行过程中达到上限,如:

复制代码
% inotifywait -r /
Setting up watches. Beware: since -r was given, this may take a while!
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'.

如果要改变这些配置,只要向相应的文件写入新值即可,如下所示:

复制代码
# cat /proc/sys/fs/inotify/max_user_watches
8192
# echo 16000 > /proc/sys/fs/inotify/max_user_watches
# cat /proc/sys/fs/inotify/max_user_watches
16000

使用 Inotify 的一些工具

近一段时间出现了很多基于 Inotify 的超炫的工具,如 incron ,它是一个类似于 cron 的守护进程 (daemon),传统的 cron 守护进程都是在规定的某个时间段内执行,而 incron 由于使用了 Inotify,可以由事件触发执行。同时 incron 的安装简单而直观,比如在 debian 上,首先在 /etc/incron.allow 中添加使用 incron 的用户 (debian 默认不允许用户使用 incron,因为如果 incron 使用不慎的话,例如形成死循环,则会导致系统宕机):

复制代码
# echo username > /etc/incron.allow

然后调用”incrontab -e“, 在弹出的编辑器中插入我们自己的规则,例如下面的这条简单的规则,文件一变化 incron 就会发邮件通知我们:

复制代码
/srv/test/ IN_CLOSE_WRITE mail -s "$@/$#\n" root

从现在开始,一旦 /src/test 文件夹中的文件被修改,就会发送一封邮件。但是注意不要让incron 监控整个子目录树,因为Inotify 只关注inodes,而不在乎是文件还是文件夹,所以基于Inotify 的软件都需要自己来处理/ 预防递归问题。关于incontab 详细使用,请参考incrontab 的manpage。

如果你还要处理incoming 文件夹,那么你可能需要 inoticoming 。当有文件进入 incoming 文件夹时 Inoticoming 就会执行某些动作,从而可以用 inoticoming 来管理 debian 的软件仓库 (例如软件仓库中一旦有上传源码包或是新添加的二进制包就立刻自动进行编译),另外,还可以用它来监控系统是否有新上传文件,如果有就发送通知。类似的工具还有 (它们都各有专长): inosync (基于消息通知机制的文件夹同步服务), iwatch (基于 Inotify 的程序,对文件系统进行实时监控),以及 lsyncd (一个守护进程 (daemon),使用 rsync 同步本地文件夹)。

Inotify 甚至对传统的 Unix 工具也进行了改进,例如 tail。使用 inotail ,同时加上 -f 选项,就可以取代每秒轮询文件的做法。此外,GNU 的 coreutils 从版本 7.5 开始也支持 Inotify 了,我们可以运行下面的命令来确认:

复制代码
# strace -e inotify_init,inotify_add_watch tail -f ~log/syslog
[...]
inotify_init() = 4
inotify_add_watch(4, "/var/log/syslog", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1

从现在开始,通过轮询来确实文件是否需要重新读取的方法应该作为古董了。

在脚本中使用 Inotify

Inotify 机制并不局限于工具,在脚本语言中也完全可以享受 Inotify 的乐趣,如 Python 中可以使用 pyinotify inotifyx ,Perl 中有 Filesys-Notify-Simple Linux-Inotify2 ,Inotify 的 Ruby 版有 ruby-inotifyrb-inoty fssm

总结

综上所述,Inotify 为 Linux 提供了一套高效监控和跟踪文件变化的机制,它可以实时地处理、调试以及监控文件变化,而轮询是一种延迟机制。对于系统管理员,关于实现事件驱动的服务如系统备份,构建服务以及基于文件操作的程序调试等,Inotify 无疑提供了强大的支持。

查看英文原文: Inotify: Efficient, Real-Time Linux File System Event Monitoring


感谢侯伯薇对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2010 年 9 月 22 日 00:0049568

评论

发布
暂无评论
发现更多内容

架构师训练营第2期-第3周作业1

xiaomao

第三周作业总结

hunk

极客大学架构师训练营

架构师训练营第 1 期第 7 周学习总结

好吃不贵

极客大学架构师训练营

架构师训练营第 1 期第 7 周作业

好吃不贵

极客大学架构师训练营

架构师训练营第 1 期 -Week7 - 课后练习

鲁小鲁

极客大学架构师训练营

架构师训练营第 1 期 - 第 7 周 - 命题作业

wgl

week3- 请在草稿纸上手写一个单例模式的实现代码,拍照提交作业

架构师训练营第一期 - 第七周学习总结

卖猪肉的大叔

极客大学架构师训练营

第三周-作业二

Mr_No爱学习

第三周作业

jingx

第三周-作业一

Geek_0b0f83

极客大学架构师训练营

架构师训练营第七周课后练习

薛凯

第三周课后练习

刘洋

极客大学架构师训练营

架构师训练营第 1 期 - 第 7周 - 学习总结

wgl

架构师训练营第七周作业

Shunyi

极客大学架构师训练营

架构师训练营第一期 - 第七周课后作业

卖猪肉的大叔

极客大学架构师训练营

装饰器模式

猴子胖胖

golang 设计模式

二期第三周作业

supersky6

第7周作业

TheSRE

极客大学架构师训练营

策略模式

猴子胖胖

golang 设计模式

架构师训练营week07作业

IT老兵重开始

第七周总结

Geek_ac4080

第 7 周 作业

Pyr0man1ac

第3周作业

Steven

极客大学架构师训练营

架构师训练营 2 期 Week03 总结

Calvin

架构师训练

第三周-总结

jizhi7

极客大学架构师训练营

周练习 7

何毅曦

第三周-作业1

Mr_No爱学习

模板方法模式

猴子胖胖

golang 设计模式

Week_07 作业

golangboy

极客大学架构师训练营

科技与产业革命的历史性交汇期,光华工程科技奖名单上的AI排面

脑极体

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

Inotify: 高效、实时的Linux文件系统事件监控框架-InfoQ