成航先森 成航先森

成都航院计算机系一个学生的个人博客

 

经验杂笔

分段图

最新文章

经验杂笔
当前位置: 首页 » 大学杂谈 » 经验杂笔 » CentOS下inotify+rsync实现文件实时同步

CentOS下inotify+rsync实现文件实时同步

编辑:狂族晨曦 来源:经验杂笔 日期:2018-02-07 阅读: 506 次 抢个沙发 百度已收录

rsync仅同步差异文件,所以传输效率较高,所以先森在项目中负载的资源服务器做了rsync同步,确保通过负载IP都能访问到相同的文件,使用crontab计划任务每1分钟执行一次同步。

计划任务最小时间刻度为1分钟(虽然可以用数学方法再调小,但是运行密度大了对服务器会造成负荷),也就是上传一张图片,最长可能要等1分钟后才能在其它服务器上访问,如果同步目录下的文件基数是百万级的,那么时间可能更久。

这种方案先森曾发过:CentOS下rsync服务器安装与配置-数据同步|文件增量备份

inotify+rsync实时同步

inotify+rsync实时同步

rsync的不足

rsync具有安全性高、备份迅速、支持增量备份等优点,通过rsync可以解决实时性不高的数据备份需求,例如定期数据库备份。

但随着业务规模的扩大,业务需求的增加,rsync的缺点也暴露出来了:

1、当文件数量大到百万级别,rsync仅差异扫描就是一项非常耗时的工作;

2、rsync自身不能实时的检测并同步数据,它总是被动的通过各种方式去触发同步。

inotify与inotify-tools

注:inotify是一个 Linux 内核特性,inotify-tools是为linux下inotify文件监控工具提供的一套C的开发接口库函数。

inotify:

inotify是一种强大的、细粒度的、异步的文件系统事件监控机制,Linux内核从2.6.13开始引入,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。

CentOS 6是已经支持的了,判断服务器是否支持inotify,只需要执行下面命令,查看是否有结果即可。

ll /proc/sys/fs/inotify

inotify-tools:

inotify-tools是为linux下inotify文件监控工具提供的一套C的开发接口库函数,同时还提供了一系列的命令行工具,这些工具可以用来监控文件系统的事件。

inotify-tools是用c编写的,除了要求内核支持inotify外,不依赖于其他。

inotify-tools提供两种工具,一是inotifywait,它是用来监控文件或目录的变化,二是inotifywatch,它是用来统计文件系统访问的次数。我们主要用到的是inotifywait工具。

inotify-tools安装

inotify-tools先森找到了两种安装方式,rpm安装和编译安装,先森用的是编译安装。

rpm安装

wget http://dl.fedoraproject.org/pub/epel/6/x86_64/Packages/i/inotify-tools-3.14-1.el6.x86_64.rpm
rpm -vhi inotify-tools-3.14-1.el6.x86_64.rpm

编译安装

编译前请确保服务器已安装编译组件:

yum install -y make  gcc gcc-c++

这个项目是发布在github上的,下载也是在github上下载。但是先森在项目首页下载下来的无法编译安装,所以安装的还是3.1.4版本的。

github项目地址:https://github.com/rvoicilas/inotify-tools/

编译安装:

wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
tar zxvf inotify-tools-3.14.tar.gz
cd inotify-tools-3.14
./configure    #或./configure --prefix=/usr/local/inotify
make
make install

安装后命令在/usr/local/bin/目录下。

查看效果:

/usr/local/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib /data/

不停止上面的命令,新建终端连接然后进入/data/文件夹进行各类操作,可以看下上面输出的结果。

rsync组合inotify-tools完成实时同步

inotify的作用,是让我们知道监控的文件夹中有变动,我们可以根据inotify输出内容,去触发rsync同步。

提示:以往使用crontab触发rsync时,我们是将rsync服务端搭建在主服务器,其他服务器去主服务器同步文件。而inotify+rsync的方式,是将rsync服务端搭建在从服务器,主服务器推送文件到从服务器,所以从服务器上的rsync配置中“read only”要配置为no,也就是“read only = no”。

inotify-tools只是个工具,并不是软件,所以要与rsync配合就需要我们自己写shell脚本,并让脚本一直运行在后台。

先森通过实际测试,整理出了两个脚本,也就是两种方案。

方案1:

#!/bin/bash
source /etc/profile
src=/data/                           # 需要同步的源路径
des=datahome                             # 目标服务器上 rsync 模块名
rsync_passwd_file=/etc/rsyncd/rsync.passwd            # rsync验证的密码文件
ipaddr=(10.0.0.1)                 # 目标服务器,多个目标服务器以空格分开
user=user                            # rsync --daemon定义的验证用户名
logs=/var/log/inotify_rsync.logs     # 日志
inotify_rsync(){
cd ${src}                              # 此方法中,由于rsync同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致,有兴趣的同学可以进行各种尝试观看其效果
/usr/local/bin/inotifywait -mrq --format  '%Xe %w%f' -e modify,create,delete,attrib,close_write,move --exclude=".*.swp" ./ | while read file         # 把监控到有发生更改的"文件路径列表"循环
do
        INO_EVENT=$(echo $file | awk '{print $1}')      # 把inotify输出切割 把事件类型部分赋值给INO_EVENT
        INO_FILE=$(echo $file | awk '{print $2}')       # 把inotify输出切割 把文件路径部分赋值给INO_FILE
        echo "-------------------------------$(date)------------------------------------"
        echo $file
        #增加、修改、写入完成、移动进事件
        #增、改放在同一个判断,因为他们都肯定是针对文件的操作,即使是新建目录,要同步的也只是一个空目录,不会影响速度。
        if [[ $INO_EVENT =~ 'CREATE' ]] || [[ $INO_EVENT =~ 'MODIFY' ]] || [[ $INO_EVENT =~ 'CLOSE_WRITE' ]] || [[ $INO_EVENT =~ 'MOVED_TO' ]]         # 判断事件类型
        then
                echo 'CREATE or MODIFY or CLOSE_WRITE or MOVED_TO'
		for ip in ${ipaddr[@]}
		do
                    rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx"  $(dirname ${INO_FILE}) ${user}@${ip}::${des} >> $logs        # INO_FILE变量代表路径哦  -c校验文件内容
		done
                 #仔细看 上面的rsync同步命令 源是用了$(dirname ${INO_FILE})变量 即每次只针对性的同步发生改变的文件的目录(只同步目标文件的方法在生产环境的某些极端环境下会漏文件 现在可以在不漏文件下也有不错的速度 做到平衡) 然后用-R参数把源的目录结构递归到目标后面 保证目录结构一致性
        fi
        #删除、移动出事件
        if [[ $INO_EVENT =~ 'DELETE' ]] || [[ $INO_EVENT =~ 'MOVED_FROM' ]]
        then
                echo 'DELETE or MOVED_FROM'
                echo 'CREATE or MODIFY or CLOSE_WRITE or MOVED_TO'
                for ip in ${ipaddr[@]}
                do
                    rsync -avzR --delete --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx"  $(dirname ${INO_FILE}) ${user}@${ip}::${des} >> $logs 
		done
                #看rsync命令 如果直接同步已删除的路径${INO_FILE}会报no such or directory错误 所以这里同步的源是被删文件或目录的上一级路径,并加上--delete来删除目标上有而源中没有的文件,这里不能做到指定文件删除,如果删除的路径越靠近根,则同步的目录月多,同步删除的操作就越花时间。这里有更好方法的同学,欢迎交流。
        fi
        #修改属性事件 指 touch chgrp chmod chown等操作
        if [[ $INO_EVENT =~ 'ATTRIB' ]]
        then
                echo 'ATTRIB'
                if [ ! -d "$INO_FILE" ]                 # 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync会顺带更新此目录。
                then
                for ip in ${ipaddr[@]}
                do
                        rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx"  $(dirname ${INO_FILE}) ${user}@${ip}::${des} >> $logs 
		done
                fi
        fi
done
inotify_rsync >> $logs 2>&1
}
inotify_rsync >> $logs 2>&1

将上面内容保存为inotify_rsync_A.sh,执行:

inotify_rsync_A.sh &

或使用screen后台启动。

另外,为避免意外遗漏文件,最好在定时任务中每隔两个小时执行一次全目录同步。

这个方案的优点:利用inotify让rsync每次仅同步有更改的文件,减少递归操作。

缺点:经过先森实际运用发现,inotify的特性,每次创建文件会产生多条输出,而这个脚本inotify的每条输出都会触发一次rsync,这样会对服务器资源产生浪费。

方案2:

为了解决方案1的问题,先森找到了另一个脚本,对方案1的脚本进行了修改:

#!/bin/bash
source /etc/profile
src=/data/                           # 需要同步的源路径
des=datahome                             # 目标服务器上 rsync 模块名
rsync_passwd_file=/etc/rsyncd/rsync.passwd            # rsync验证的密码文件
ipaddr=(10.0.0.1)                 # 目标服务器,多个目标服务器以空格分开
user=user                            # rsync --daemon定义的验证用户名
inlogs=/var/log/inotifywait.logs
logs=/var/log/inotify_rsync.logs
errlog=/var/log/inotify_rsync.err.logs
cd ${src}                              # 此方法中,由于rsync同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致,有兴趣的同学可以进行各种尝试观看其效果
/usr/local/bin/inotifywait -mrq --format  '%Xe %w%f' -e modify,create,delete,attrib,close_write,move --exclude=".*.swp" ./ >> $inlogs &
while true;do
     if [ -s ${inlogs} ];then
        grep -i -E "delete|moved_from" ${inlogs} >> /var/log/inotify_away.log
		for ip in ${ipaddr[@]}
		do
			rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx" ${src} ${user}@${ip}::${des} >> $logs
			RETVAL=$?
		done
		#同步失败后的输出日志
        if [ $RETVAL -ne 0 ];then
           echo "${src} sync to ${ipaddr} failed at `date +"%F %T"`,please check it by manual" >> $errlog
        fi
        cat /dev/null > $inlogs
		for ip in ${ipaddr[@]}
		do
			rsync -avzcR --password-file=${rsync_passwd_file} --exclude="*.swp" --exclude="*.swx" ${src} ${user}@${ip}::${des} >> $logs
		done
    else
        sleep 1
    fi
done

这个脚本是将inotify的检测内容输出到文件/var/log/inotifywait.logs,脚本判断这个文件是否为空,非空则表明有变动,那么就来一次完整的同步。如果文件为空则睡眠1秒。

将上面内容保存为inotify_rsync_B.sh,执行:

inotify_rsync_B.sh &

这个方案的优点:不会根据inotify输出重复触发rsync同步。

缺点:每次都是rsync完整同步,如果文件数量较大则对比时间会比较长。

inotify优化

inotify检查磁盘变动是有队列等值的配置的,inotify默认内核参数值太小,会导致实际检测的时候报错。

查看系统默认参数值

sysctl -a | grep max_queued_events
sysctl -a | grep max_user_watches
sysctl -a | grep max_user_instances

临时修改

sysctl -w fs.inotify.max_queued_events="99999999"
sysctl -w fs.inotify.max_user_watches="99999999"
sysctl -w fs.inotify.max_user_instances="65535"

固定修改:vim /etc/sysctl.conf #添加以下代码

fs.inotify.max_queued_events=99999999
fs.inotify.max_user_watches=99999999
fs.inotify.max_user_instances=65535

标签:
除特别注明外,本站所有文章均为成航先森 www.capjsj.cn原创,本文共7357个字
转载请注明出处来自http://www.capjsj.cn/inotify_rsync.html
已有 0 位"计工"发布了激烈的评论,还有N多人围观笑而不语评论
匿名的头像
欢迎发表评论
取消评论

表情
疑问调皮伤心抠鼻黑线微笑可爱奸笑震惊吓到了撇嘴大兵忍不住笑笑狂骂狂怒噢?鼓掌酷⊙﹏⊙b汗鄙视大哭嘿嘿

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
官方微信
发表评论 返回顶部