一、Inotify介绍:

      Inotify 是一个 Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如删除、读、写和卸载操作等。您还可以跟踪活动的源头和目标等细节。

使用 inotify 很简单:创建一个文件描述符,附加一个或多个监视器(一个监视器 是一个路径和一组事件),然后使用 read 方法从描述符获取事件。read 并不会用光整个周期,它在事件发生之前是被阻塞的。

       内核版本不低于 2.6.13,系统就支持 inotify。  同时可以查看内核参数


[root@localhost inotify]# cd /proc/sys/fs/inotify/
[root@localhost inotify]# ll
total 0
-rw-r--r-- 1 root root 0 Aug 29 17:20 max_queued_events
-rw-r--r-- 1 root root 0 Aug 29 17:20 max_user_instances
-rw-r--r-- 1 root root 0 Aug 29 17:20 max_user_watches
[root@localhost inotify]# cat *
16384
128
8192


      

       notify-tools 是为linux下inotify文件监控工具提供的一套c的开发接口库函数,同时还提供了一系列的命令行工具,这些工具可以用来监控文件系统的事件。 inotify-tools是用c编写的,除了要求内核支持inotify外,不依赖于其他。inotify-tools提供两种工具,一是 inotifywait,它是用来监控文件或目录的变化,二是inotifywatch,它是用来统计文件系统访问的次数。现在介绍一下它的使用方法。


      查看notify-tools信息:  https://github.com/rvoicilas/inotify-tools/wiki


      结合rsync进行测试,脚本如下:


#!/bin/sh

cmd=`which inotifywait`
$cmd -mrq --timefmt "%F %T" --format "%T %f"  -e create,close_write,attrib /data  | while read date time file
do
  cd /data && rsync -azv $file cms@192.168.2.207::data --password-file=/etc/rsyncd.pass
done

注:加上delete事件会导致删除同步错误,提示文件不存在,故删除事件单独启个脚本进程。




      性能测试:

           针对大量的小文件 ,同步小文件太慢,直接同步目录

           10-100k的小文件,并发达到200-300,需要对内核三个参数进行调优

           max_queued_events: 320000  max_user_watches:5000000


在对一个大磁盘进行inotify监听时,爆出如下错误:

Failed to watch /home/;

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一下这个文件,默认值是8192,echo 8192000 > /proc/sys/fs/inotify/max_user_watches即可



二、sersync介绍:

sersync利用inotifyrsync对服务器进行实时同步,其中inotify用于监控文件系统事件,rsync是目前广泛使用的同步算法,其优点是只对文件不同的部分进行操作,所以其优势大大超过使用挂接文件系统的方式进行镜像同步。由金山的周洋开发完成,是目前使用较多的文件同步工具之一。该工具和其他的工具相比有如下优点:

  • sersync是使用c++编写,由于只同步发生更改的文件,因此比其他同步工具更节约时间、带宽;

  • 安装方便、配置简单;

  • 使用多线程进行同步,能够保证多个服务器实时保持同步状态;

  • 自带出错处理机制,通过失败队列对出错的文件重新出错,如果仍旧失败,则每10个小时对同步失败的文件重新同步;

  • 自带crontab功能,只需在xml配置文件中开启,即可按您的要求,隔一段时间整体同步一次;

  • 自带sockethttp协议扩展,你可以方便的进行二次开发;


    线程组线程是等待线程队列的守护线程,当队列中有数据的时候,线程组守护线程逐个唤醒,当队列中inotify事件交多的时候就会被全部唤醒一起工作。这样设计的目的是能够同时处理多个inotify事件,重发利用服务器的并发能力(核数*2+2)。

      之所以称之为线程组线程,是因为每个线程在工作的时候,会根据服务器的数量建立子线程,子线程可以保证所有的文件与各个服务器同时同步,当要同步的文件较大的时候,这样设计可以保证各个远程服务器可以同时获得要同步的文件。

       服务线程的作用有三个,首先是处理同步失败的文件,将这些文件 再次同步,对于再次同步失败的文件会生成rsync_fail_log.sh脚本,记录失败的事件。同时每隔10个小时执行脚本一次,同时清空脚本。服务 线程的第三个作用是crontab功能,可以每隔一定时间,将所有路径整体同步一次。

    过滤队列的建立是为了过滤短时间内产生的重复的inotify信息,例如在删除文件夹得时候,inotify就会同时产生删除文件夹里的文件与删除文件夹 得事件,通过过滤队列当删除文件夹事件产生的时候,会将之前加入队列的删除文件的事件全部过滤掉,这样只产生一条事件减轻了同步的负担。同时对于修改文件 的操作的时候,会产生临时文件与重复操作。

   

配置文件说明:

下面做逐行的进行解释说明:
1、 <host hostip="localhost" port="8008"></host>
hostip与port是针对插件的保留字段,对于同步功能没有任何作用,保留默认即可。

2、filter文件过滤功能
对于sersync监控的文件,会默认过滤系统的临时文件(以“.”开头,以“~”结尾),除了这些文件外,可以自定义其他需要过滤的文件。
    <filter start="true">
        <exclude expression="(.*)\.svn"></exclude>
        <exclude expression="(.*)\.gz"></exclude>
        <exclude expression="^info/*"></exclude>
        <exclude expression="^static/*"></exclude>
        <exclude expression="^APK/*"></exclude>
        <exclude expression="^IOSIPA/*"></exclude>
    </filter>
start设置为 true, 在exclude标签中,填写正则表达式,默认给出两个例子分别是过滤以".gz"结尾的文件与过滤监控目录下的info路径(监控路径/info /*),可以根据需要添加,但开启的时候,自己测试一下,正则表达式如果出现错误,控制台会有提示。相比较使用rsync 的exclude功能,被过滤的路径,不会加入监控,大大减少rsync的通讯量。


3、inotify监控参数设定(优化)
对于inotify监控参数可以进行设置,根据您项目的特点优化srsync。
    <inotify>
        <delete start="true"/>
        <createFolder start="true"/>
        <createFile start="false"/>
        <closeWrite start="true"/>
        <moveFrom start="true"/>
        <moveTo start="true"/>
        <attrib start="true"/>
        <modify start="true"/>
    </inotify>
对于大多数应用,可以尝试把createFile(监控文件事件选项)设置为false来提高性能,减少 rsync通讯。因为拷贝文件到监控目录会产生create事件与close_write事件,所以如果关闭create事件,只监控文件拷贝结束时的事 件close_write,同样可以实现文件完整同步。
注意:强将createFolder保持为true,如果将createFolder设为false,则不会对产生的目录进行监控,该目录下的子文件与子目录也不会被监控。所以除非特殊需要,请开启。
默认情况下对创建文件(目录)事件与删除文件(目录)事件都进行监控,如果项目中不需要删除远程目标服务器的文件(目录),则可以将delete 参数设置为false,则不对删除事件进行监控。


4、失败日志脚步配置

<failLog path="/opt/sersync/log/rsync_fail_log.log" timeToExecute="60"/>

对于失败的传输,会进行重新传送,再次失败就会写入rsync_fail_log,然后每隔一段时间(timeToExecute进行设置)执行该脚本再次重新传送,然后清空该脚本。可以通过path来设置日志路径。


5、Crontab定期整体同步功能

        <crontab start="false" schedule="24000"><!--600mins-->
            <crontabfilter start="false">
                <exclude expression="*.php"></exclude>
                <exclude expression="info/*"></exclude>
            </crontabfilter>
        </crontab>

crontab可以对监控路径与远程目标主机每隔一段时间进行一次整体同步,可能由于一些原因两次失败重传都失败了,这个时候如果开启了crontab功能,还可以进一步保证各个服务器文件一致,如果文件量比较大,crontab的时间间隔要设的大一些,否则可能增加通讯开销。schedule这个参数是设置crontab的时间间隔,默认是600分钟
如果开启了filter文件过滤功能,那么crontab整体同步也需要设置过滤,否则虽然实时同步的时候文件被过滤了,但crontab整体同步的时候如果不单独设置crontabfilter,还会将需过滤的文件同步到远程,crontab的过滤正则与filter过滤的不同,也给出了两个实例分别对应与过滤文件与目录。总之如果同时开启了filter与crontab,则要开启crontab的crontabfilter,并按示例设置使其与filter的过滤一一对应。


6、插件相关


        <plugin start="false" name="command"/>
    </sersync>

    <plugin name="command">
        <param prefix="/bin/sh" suffix="" ignoreError="true"/>  <!--prefix /opt/tongbu/mmm.sh suffix-->
        <filter start="false">
            <include expression="(.*)\.php"/>
            <include expression="(.*)\.sh"/>
        </filter>
    </plugin>

    <plugin name="socket">
        <localpath watch="/opt/fileserver">
            <deshost ip="192.168.100.160" port="8009"/>
        </localpath>
    </plugin>

    <plugin name="refreshCDN">
        <localpath watch="/data0/htdocs/cms.xoyo.com/site/">
            <cdninfo domainname="ccms.chinacache.com" port="80" username="xxxx" passwd="xxxx"/>
            <sendurl base="http://pic.xoyo.com/cms"/>
            <regexurl regex="false" match="cms.xoyo.com/site([/a-zA-Z0-9]*).xoyo.com/p_w_picpaths"/>
        </localpath>
    </plugin>


如上面的xml所示,其中plugin标签设置为true时候,在同步文件或路径到远程之后后,调用插件。通过name参数指定需要执行的插件。目前支持的有command refreshCDN socket http四种插件。http插件目前由于兼容性原因去除,以后会重新加入。

command插件当文件同步完成后,会调用command插件,如同步文件是test.php,则test.php文件在改动之后,调用rsync同步到远程服务器后,调用command插件,执行

/bin/sh test.php  suffix>/dev/null 2>&1

如果
suffix
设置了,则会放在inotify事件test.php之后
如果ignoreError为true,则会添加>/dev/null 2>&1
当然还可以设置command的filter,当filter为ture,include可以只对正则匹配到的文件,调用command。


刷新CDN插件“refreshCDN”,就在同步过程中将文件发送到目的服务器后刷新cdn接口。如果不想使用,则将start属性设为false即可。如果需要使用其他插件,则查看其他plugin标签,将插件名称改为 xml中其它插件的名称即可。

       以下模块(refreshCDN http socket)可以单独使用,只需在命令行下使用-m 参数即可。如果需要作为插件与同步程序一起使用,见同步程序说明的插件配置。

      该模块根据chinaCDN的协议,进行设计,当有文件产生的时候,就向cdn接口发送需要刷新的路径位置。刷新CDN模块需要配置的xml文件如下。


其中 localpath watch 是需要监控的目录。

cdnifo标签制定了cdn接口的域名,端口号,以及用户名与密码。

sendurl标签是需要刷新的url的前缀。

regexurl标签中的,regex属性为true时候,使用match属性的正则语句匹配inotify返回的路径信息,并将正则匹配到的部分作为url一部分,

举例:

如果产生文件事件为:/data0/htdoc/cms.88181.com/site/jx3.88181.com/p_w_picpath/a/123.txt

经过上面的match正则匹配后,最后刷新的路径是:

http://pic.88181.com/cms/jx3/a/123.txt;

如果regex属性为false,最后刷新的路径是

http://pic.88181.com/cms/jx3.88181.com/p_w_picpaths/a/123.txt;


三、inotify及sersync压力测试

环境介绍:

   172.16.171.100    测试客户机、nfs客户端

   172.16.171.110    inotify、sersync端 、nfs服务端

   172.16.171.120    rsync服务端

   均为CentOS release 6.6 64位系统,4核2G


1、测试脚本介绍:


[root@openstack-nova test]# ll
total 61680
-rw-r--r--. 1 root root  1024000 Aug 30 11:27 1000k.txt
-rw-r--r--. 1 root root   102400 Aug 30 11:27 100k.txt
-rw-r--r--. 1 root root    10240 Aug 30 10:28 10k.txt
-rw-r--r--. 1 root root 10240000 Aug 30 11:39 10m.txt
-rw-r--r--. 1 root root   512000 Aug 30 11:27 500k.txt
-rw-r--r--. 1 root root    51200 Aug 30 10:28 50k.txt
-rw-r--r--. 1 root root 51200000 Aug 30 11:39 50m.txt
-rwxr-xr-x. 1 root root      313 Aug 30 11:09 test.sh



cat test.sh


#!/bin/sh

count=20
a=1

name=$1
num=$2
file=$3
while [ "$a" -le "$num" ]
do
   for ((i=1;i<=$count;i++))
    do
       [ ! -e /cms/$name/$i ] &&  /bin/mkdir /cms/$name/$i
       /bin/cp ${file}.txt /cms/$name/$i/${file}_`echo $(date)$RANDOM | md5sum | cut -c 1-8`.txt
    done
   a=`expr $a + 1`

   sleep 1

done



2、针对sersync目录进行10K、500K、1000K、10M测试,测试命令如下:

sh test.sh sersync 20 10k

sh test.sh sersync 20 500k

sh test.sh sersync 20 1000k

sh test.sh sersync 20 10m

172.16.171.110(sersync端)和172.16.171.120(rsync)端查看统计命令:

while true; do tree sersync/ | wc -l; sleep 1 ;done | tee -a sersync.log

结果如下:


ids(10k)r(10k)s(500k)r(500k)s(1m)r(1m)s(10m)r(10m)
133333333
24336433943142111
36353635443434330
47863786363634543
58383838383835951
6103103103103103986363
71231231231231231107064
81431431431431251237469
91631531631531431437471
101821631721631631637573
111831831831831831837773
122032032032032031937776
132232232232232142037877
142432432432352232238083
152632532592472432438283
162832632632632632588384
172842832832832812668885
183033033033032832839088
193233233233233033039490
203433433433333233239995
2136335934834334333310096
2238337236336335234310099
23392383383383363363102100
24403403403403383383103103
25423423423416403399109103
26


423421408112106
27



423423115107


从统计结束来看:

在172.16.171.110上直接生成文件

文件大小在1M之内的小文件,同步效率在秒级。

10M的大文件sersync端使用了126秒,rsync端同步完成共使用了161秒。


在172.16.171.100上以nfs挂载,并批量生成文件进行测试。

10K文件使用28-29秒,500K文件使用45秒,1M文件使用70秒,10M文件使用279秒,同步完成使用281秒



3、针对inotify目录进行10K、500K、1000K、10M测试,测试命令如下:

sh test.sh inotify 20 10k

sh test.sh inotify 20 500k

sh test.sh inotify 20 1000k

sh test.sh inotify 20 10m

172.16.171.110(inotify端)和172.16.171.120(rsync)端查看统计命令:

while true; do tree inotify/ | wc -l; sleep 1 ;done | tee -a inotify.log

结果如下:


ids(10k)r(10k)s(500k)r(500k)s(1m)r(1m)s(10m)r(10m)
133333333
2434343434337438
36363635663544829
48382806383666332
58383838384837737
61031031031031031038042
71231231231231231238343
814314314314314313710343
916316316315616315011044
1018317217116617616611547
1118618318318318318311747
1220320320320320320312347
1322322322322322322312348
1424324324324124323612454
1526326326324725924512558
1628327126426326326313663
1728828628328328328313664
1830330330330330330113964
1932332332332332331314064
2034334334333633332314364
2136336335534634334314366
2238338336336336336314371
2339439338338338337815072
2440340340340340339115872
2542342342342141440516072
26


42342342316372


从统计结束来看:

在172.16.171.110上直接生成文件

文件大小在1M之内的小文件,同步效率在秒级,和sersync效率不相上下。

10M的大文件inotify端使用了103秒,rsync端同步完成使用了410秒,要远远超过sersync。


在172.16.171.100上以nfs挂载,并批量生成文件进行测试。

10K文件使用28-29秒,500K文件使用41秒,1M文件使用50秒,10M文件使用210秒,同步完成使用216秒


总结:当并发大量生成大文件时,sersync因多线程效率会高点,当并发量一般时,感觉inotify效率更高点。