日期:2014-05-16  浏览次数:20766 次

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

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

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

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

通常使用文件轮询的通知机制,但是这种机制只适用于经常改变的文件(因为它可以确保每过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

下载inotify  ;   地址:http://inotify-tools.sourceforge.net/

   编译安装

./configure
make
make install
安装完毕后会有一个inotifywait命令,可以通过man inotifywait 查看具体的命令帮助。
主要通过inotifywait 监控具体目录和文件的变动。
   
inotify 可以监视的文件系统事件包括:
   
  IN_ACCESS,即文件被访问
  IN_MODIFY,文件被 write
  IN_ATTRIB,文件属性被修改,如 chmod、chown、touch 等
  IN_CLOSE_WRITE,可写文件被 close
  IN_CLOSE_NOWRITE,不可写文件被 close
  IN_OPEN,文件被 open
  IN_MOVED_FROM,文件被移走,如 mv
  IN_MOVED_TO,文件被移来,如 mv、cp
  IN_CREATE,创建新文件
  IN_DELETE,文件被删除,如 rm
  IN_DELETE_SELF,自删除,即一个可执行文件在执行时删除自己
  IN_MOVE_SELF,自移动,即一个可执行文件在执行时移动自己
  IN_UNMOUNT,宿主文件系统被 umount
  IN_CLOSE,文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
  IN_MOVE,文件被移动,等同于(IN_MOVED_FROM | IN_MOVED_TO)

  注:上面所说的文件也包括目录。


    inotifywait 命令的常用参数包括:
    -m, --monitor      保持一直监听
    -r, --recursive    若有多级目录循环递归每一层。
    -q, --quiet        静默式运行
    -e <event>, --event <event>  create,move,delete,modify

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

好的开始是成功的一半,对于了解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,