inotify 简介
是一个内核用于通知用户空间程序文件系统变化的机制,是一种强大的、细颗粒的、异步的文件系统监控机制,内核从2.6.13起,加入Inotify可以监控文件系统中添加、删除、修改移动等各种事件,利用这个内核接口,就可以监控文件系统下文件的各种变化情况。
安装
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
yum -y install inotify-tools
一共安装了2个工具,即inotifywait和inotifywatch
inotifywait:在被监控的文件或目录上等待特定文件系统事件(open,close,delete等)发生,执行后处于阻塞状态,适合shell脚本中使用。
inotifywatch:收集被监视的文件系统使用度统计数据,指文件系统事件发生的次数统计。
语法格式
inotifywait
-mrq --
format
'%Xe %w%f'
-e modify,create,delete,attrib
/data/
执行上面命令,是让inotifywait监听/data/目录,当监听到有发生modify,create,delete,attrib等事件发生时,按%Xe %w%f的格式输出。
inotifywait 参数说明
参数名称 | 参数说明 |
---|---|
-m,–monitor | 始终保持事件监听状态 |
-r,–recursive | 递归查询目录 |
-q,–quiet | 只打印监控事件的信息 |
–excludei | 排除文件或目录时,不区分大小写 |
-t,–timeout | 超时时间 |
–timefmt | 指定时间输出格式 |
–format | 指定时间输出格式 |
-e,–event | 后面指定删、增、改等事件 |
-e :--event的各种事件含义
access 文件或目录被读取 modify 文件被改动(不涉及目录),有以下几种请况 1.vi 文件(无论存在与否)未作更改,显示为*.swp vi 文件做更改,wq退出,显示为file/file.swp 2.command >>或> file,无论file 存在与否 attrib 文件或目录属性(时间戳、属组/主,其他拓展属性)被改变,递归改变目录属性时那么所有子目录也会列出。注意touch 文件也会监控到 1.chown root:root /opt/ -R 把所有的被改变属性目录全部列出,文件表示为:“ATTRIB” ,目录标识为:“ATTRIBXISDIR” close_write 监控文件以可以写入的模式被打开的文件“被关闭”的事件 1.vi 与modify 类似,有swp或swpx 产生 2.command >>/> 与modify 类似 close_nowrite 监控文件被以只读的模式打开后的关闭事件(打开文件之前打开的目录也会记录) cat/less/more 目录标识为:“CLOSE_NOWRITEXCLOSEXISDIR” 文件标识为:CLOSE_NOWRITEXCLOSE close 包括 close_write and close_nowrite open 打开文件事件,与close 正好相反 moved_to 被监控的目录内的目录或文件被改名(位置不变),其他位置的文件/目录被移动到被监控的目录内 文件标识为:MOVED_TO 目录标识为:MOVED_TOXISDIR moved_from 被监控的目录内的目录或文件被改名(位置不变),被监控的目录内目录/文件被移动到其他位置 move both moved_to and moved_from move_self 监控事件为:被监控的目录/文件本身被改名/移动,注意文件/目录被改动后,也就无法监控了 create 文件/目录被创建,vi 即使不保存也会生成swp 输出 CREATE/CREATEXISDIR delete 文件/目录被删除,vi编辑时也会发生删除swp,swxp 文件的事件 DELETE delete_self 删除监控的文件/目录本身的事件,注意只是本身而不是子目录或文件,但是删除的本身目录如果有子目录一并输出;一旦被删除,即使再创建再删除也不会再监控此事件, 除非创建后重新开启监控命令。 DELETE_SELF DELETE_SELF /opt/local/dir11/dir2/dir3/dir4/dir5/ DELETE_SELF /opt/local/dir11/dir2/dir3/dir4/ DELETE_SELF /opt/local/dir11/dir2/dir3/ DELETE_SELF /opt/local/dir11/dir2/ DELETE_SELF /opt/local/dir11/ DELETE_SELF /opt/local/ unmount 监控被监控的目录被卸载事件,注意目录被卸载后,事件对象显示被卸载目录包括了监控目录的各个子目录; 一旦被卸载即可再挂载也不会再监控此事件了,触发先挂载前提下再重新监控目录 UNMOUNT /mnt/repodata/ UNMOUNT /mnt/Packages/ UNMOUNT /mnt/isolinux/ UNMOUNT /mnt/images/pxeboot/ UNMOUNT /mnt/images/ UNMOUNT /mnt/EFI/BOOT/ UNMOUNT /mnt/EFI/ UNMOUNT /mnt/
inotifywait + rsync
用inotify+rsync做实时同步达到分布式系统配置的一致性的目的
网上常见的脚本
#!/bin/bash /usr/bin/inotifywait -mrq --format '%w%f'-e create,close_write,delete /backup |while read file #把发生更改的文件列表都接收到file 然后循环,下面的命令都没有引用这个$file 下面做的是全量rsync do cd /backup && rsync -az --delete /backup/ rsync_backup@192.168.1.101::backup/--password-file=/etc/rsync.password done
上述脚本,在监控的目录文件很大的请况下同步效率很低,无法做到实时性。原因是inotifywait 监控到的任何在backup目录下的特定事件都会触发管道后while内的rsync操作,rsync
扫描的是/bakcup 的整个目录根据文件变化同步,而不是只扫描同步发生变化的字目录/文件。
改良后的版本
#!/bin/bash rsync_passwd_file=/etc/rsync2.pass ip1=192.168.1.101 user=root src=/data/ des=test cd ${src} #由于rsync -R参数同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致 /usr/local/inotify/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib,close_write,move ./ | while read file do INO_EVENT=$(echo $file | awk '{print $1}') # 把inotify输出切割 把事件类型部分赋值给INO_EVENT INO_FILE=$(echo $file | awk '{print $2}') # 把inotify输出切割 把文件路径部分赋值给INO_FILE #增加、修改、写入完成、移动进事件。增、改放在同一个判断,因为他们都肯定是针对文件的操作,即使是新建目录,要同步的也只是一个空目录,不会影响速度。 if [[ $INO_EVENT =~ 'CREATE' ]]||[[ $INO_EVENT =~ 'MODIFY' ]]||[[ $INO_EVENT =~ 'CLOSE_WRITE' ]]||[[ $INO_EVENT =~ 'MOVED_TO' ]]&&[[ ! $INO_FILE =~ '.swp' ]];then # 判断事件类型 rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} --exclude='services/*/logs' # -c校验文件内容,-R参数把源的目录结构递归到目标后面保证目录结构一致性,注意-R只同步源文件和源文件所在的绝对路径的目录结构,不同步目录内的其他文件 #上面的rsync同步命令 源是用了$(dirname ${INO_FILE})变量即每次只针对性的同步发生改变的文件的目录(只同步目标文件的方法在生产环境的某些极端环境下会漏文件现在可以在不漏文件下也有不错的速度做到平衡) elif [[ $INO_EVENT =~ 'DELETE' ]]||[[ $INO_EVENT =~ 'MOVED_FROM' ]];then rsync -avzR --delete --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} --exclude='services/*/logs' #如果直接同步已删除的路径${INO_FILE}会报no such or directory错误所以这里同步的源是被删文件或目录的上一级路径,并加上--delete来删除目标上有而源中没有的文件,这里不能做到指定文件删除,如果删除的路径越靠近根,则同步的目录越多,同步删除的操作就越花时间。 elif [[ $INO_EVENT =~ 'ATTRIB' ]]&&[ ! -d "$INO_FILE" ]&&[[ ! $INO_FILE =~ '.swp' ]];then # 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync会顺带更新此目录。 rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} --exclude='services/*/logs' done
每两小时做1次全量同步
因为inotify只在启动时会监控目录,他没有启动期间的文件发生更改,他是不知道的,所以这里每2个小时做1次全量同步,防止各种意外遗漏,保证目录一致。
crontab
-e
* *
/2
* * *
rsync
-avz --password-
file
=
/etc/rsync-client
.pass
/data/
root@192.168.1.101::data
说明:
1.为了提高同步效率,只针对发生变化的目录/文件的上一级目录进行同步,此处使用了dirname
rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::test
2.-R 参数的目的是同步发生变化的文件和文件的目录结构。例如监控的/data 目录,操作touch /data/test/a.txt , 使用了dirname 得到的是不带后缀“/”的目录/data/test ,所以同步的 是 test整个目录,但是-R 参数表示会同步新建文件a.txt 以及a.txt 的绝对路径的目录结构/data/test ,注意只同步目录结构不会同步/data/test/内的其他子文件和目录。 所以此时出 现了一个问题就是会把整个data 目录同步到对端的目录下,即在对端目录下创建整个data目录,而我们的初衷是data 和对端目录两个目录之间数据同步,此时通过cd 监控目录,再 inotifywait ./目录,再发生变化后dirname 后得到的路径就是 ./../.. 结构,-R参数同步的就是当前目录下的绝对路径了。
3.由于rsync -R参数同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致,详见2说明
cd ${src} /usr/local/inotify/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib,close_write,move ./ | while read file
4. 关于 .swp 是vi 命令时产生的临时的交换文件,此文件产生时不必同步,所以要排除。
5.设计到日志等文件时不需要同步,此时使用了 --exclude='services/*/logs' ,排除了./services/*/logs目录的同步,注意此处使用了通配符 “*”,另外需要注意的是需要删除时,使用的 是--delete ,同时使用delete exclude 那么排除的文件不会 被delete 删除。
inotify 优化
# 在/proc/sys/fs/inotify目录下有三个文件,对inotify机制有一定的限制
[root@web ~]
# ll /proc/sys/fs/inotify/
总用量0
-rw-r--r--1 root root 09月923:36 max_queued_events
-rw-r--r--1 root root 09月923:36 max_user_instances
-rw-r--r--1 root root 09月923:36 max_user_watches
参数含义
max_user_watches #设置inotifywait或inotifywatch命令可以监视的文件数量(单进程)
max_user_instances #设置每个用户可以运行的inotifywait或inotifywatch命令的进程数
max_queued_events #设置inotify实例事件(event)队列可容纳的事件数量
临时生效(可以改配置文件永久生效)
echo 50000000>/proc/sys/fs/inotify/max_user_watches -- 把他加入/etc/rc.local就可以实现每次重启都生效
echo 50000000>/proc/sys/fs/inotify/max_queued_events