Rsync+inotify实现文件实时同步#附shell脚本

时间:2021-10-16 10:38:11

强烈推荐先仔细看此文

https://segmentfault.com/a/1190000002427568

实验环境

centos 7.3
vm2:192.168.221.128 同步服务器
vm1:192.168.221.129 上传服务器
关闭seliunx
关闭防火墙

同步服务器vm2的配置

yum install rsync
创建rsyncd.conf配置文件:
log file = /var/log/rsyncd.log
pidfile = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
secrets file = /etc/rsync.pass #用户认证配置文件,里面保存用户名称和密码,后面会创建这个文件
motd file = /etc/rsyncd.Motd #rsync启动时欢迎信息页面文件位置(文件内容自定义)

[Sync] #同步模块名称
path = /data/wwwroot/sync/ #rsync服务端数据目录路径(最后面的“/”很重要)
comment = Sync
uid = root
gid = root
port=873
use chroot = no
read only = no
list = no #不显示rsync服务端资源列表
max connections = 200
timeout = 600
auth users = root #执行数据同步的用户名,可以设置多个,用英文状态下逗号隔开
hosts allow = 192.168.221.129#允许进行数据同步的客户端IP地址,可以设置多个,用英文状态下逗号隔开
hosts deny = 0.0.0.0/32
创建用户认证文件
#vim /etc/rsync.pass
user1:123456 #格式,用户名:密码,可以设置多个,每行一个用户名:密码
设置文件权限
chmod 600 /etc/rsyncd.conf #设置文件所有者读取、写入权限
chmod 600 /etc/rsync.pass #设置文件所有者读取、写入权限
启动rsync
#/usr/bin/rsync --daemon --config=/etc/rsyncd.conf
daemon模式:使用TCP直接连接rsync daemon。当源路径或目的路径的主机名后面包含两个冒号,或使用rsync://URL时使用这种模式,无需远程shell,但必须在一台机器上启动rsync daemon,默认端口873,这里可以通过rsync --daemon使用独立进程的方式,或者通过xinetd超级进程来管理rsync后台进程。
当rsync作为daemon运行时,它需要一个用户身份。如果你希望启用chroot,则必须以root的身份来运行daemon,监听端口,或设定文件属主;如果不启用chroot,也可以不使用root用户来运行daemon,但该用户必须对相应的模块拥有读写数据、日志和lock file的权限。当rsync以daemon模式运行时,它还需要一个配置文件——rsyncd.conf。修改这个配置后不必重启rsync daemon,因为每一次的client连接都会去重新读取该文件。

发布服务器vm1的配置

#yum install rsync
创建认证密码文件
vim /etc/passwd.txt
123456 #只需要填写密码即可,不用像rsync.pass需要用“用户:密码”的格式

chmod 600 /etc/passwd.txt #设置文件权限,只设置文件所有者具有读取、写入权限即可
验证同步传输

在发布服务器vm1上操作

#将发布服务器vm1的文件同步到同步服务器vm2

rsync -avH --port=873 --progress --delete /data/wwwroot/sync/ root@192.168.221.128::Sync --password-file=/etc/passwd.txt

#将同步服务器vm2的文件同步到发布服务器vm1

rsync -avH --port=873 --progress --delete root@192.168.221.128::Sync --password-file=/etc/passwd.txt /data/wwwroot/sync

!!!这里在正式环境上操作一定要注意两种同步命令的差别,不然会导致文件删除

- 删除/root/下的文件不会同步删除/tmp/rsync_bak,除非加入--delete选项
- 文件访问时间等属性、读写等权限、文件内容等有任何变动,都会被认为修改
- 目标目录下如果文件比源目录还新,则不会同步
- 源路径的最后是否有斜杠有不同的含义:有斜杠,只是复制目录中的文件;没有斜杠的话,不但要复制目录中的文件,还要复制目录本身

安装使用inotify

rsync不能实时的去监测、同步数据,虽然它可以通过crontab方式进行触发同步,但是两次触发动作一定会有时间差,这样就导致了服务端和客户端数据可能出现不一致,无法在应用故障时完全的恢复数据。基于以上原因,rsync+inotify组合出现了

1、查看服务器内核是否支持inotify
#ll /proc/sys/fs/inotify #列出文件目录,出现下面的内容,说明服务器内核支持inotify
-rw-r--r-- 1 root root 0 Mar 7 02:17 max_queued_events
-rw-r--r-- 1 root root 0 Mar 7 02:17 max_user_instances
-rw-r--r-- 1 root root 0 Mar 7 02:17 max_user_watches
注:Linux下支持inotify的内核最小为2.6.13

2、安装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 --prefix=/usr/local/inotify&& make && make install

3、修改inotify默认参数(inotify默认内核参数值太小)
查看系统默认参数值
sysctl -a | grep max_queued_events
结果是:fs.inotify.max_queued_events = 16384
sysctl -a | grep max_user_watches
结果是:fs.inotify.max_user_watches = 8192
sysctl -a | grep max_user_instances
结果是:fs.inotify.max_user_instances = 128

#vi /etc/sysctl.conf #添加以下代码,修改参数
fs.inotify.max_queued_events=99999999
fs.inotify.max_user_watches=99999999
fs.inotify.max_user_instances=65535

4、sysctl -p生效,系统重启后也可以正常工作

参数说明:
max_queued_events:
inotify队列最大长度,如果值太小,会出现"** Event Queue Overflow **"错误,导致监控文件不准确
max_user_watches:
要同步的文件包含多少目录,可以用:find /home_test -type d | wc -l 统计,必须保证max_user_watches值大于统
计结果(这里/home_test为同步文件目录)
max_user_instances:
每个用户创建inotify实例最大值
inotify-tools

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

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

这一步的核心其实就是在客户端创建一个脚本rsync.sh,适用inotifywait监控本地目录的变化,触发rsync将变化的文件传输到远程备份服务器上

创建排除在外不同步的文件列表
排除不需要同步的文件或目录有两种做法:
第一种是inotify监控整个目录,在rsync中加入排除选项,简单
第二种是inotify排除部分不监控的目录,同时rsync中也要加入排除选项,可以减少不必要的网络带宽和CPU消耗
我们选择第二种
inotifywait排除

这个操作在客户端进行,假设/tmp/src/mail/2014/以及/tmp/src/mail/2015/cache/目录下的所有文件不用同步,所以不需要监控,/tmp/src/下的其他文件和目录都同步

其实对于打开的临时文件,可以不监听modify时间而改成监听close_write

inotifywait排除监控目录有--exclude 和--fromfile 两种格式,并且可以同时使用,但主要前者可以用正则,而后者只能是具体的目录或文件。

# vi /etc/inotify_exclude.lst:
/tmp/src/pdf
@/tmp/src/2014

使用fromfile格式只能用绝对路径,不能使用诸如*正则表达式去匹配,@表示排除。
如果要排除的格式比较复杂,必须使用正则,那只能在inotifywait中加入选项

--exclude '(.*/*\.log|.*/*\.swp)$|^/tmp/src/mail/(2014|201.*/cache.*)'

表示排除/tmp/src/mail/以下的2014目录,和所有201*目录下的带cache的文件或目录,以及/tmp/src目录下所有的以.log或.swp结尾的文件。

rsync排除

使用inotifywait排除监控目录的情况下,必须同时使用rsync排除对应的目录,否则只要有触发同步操作,必然会导致不该同步的目录也会同步。与inotifywait类似,rsync的同步也有--exclude和--exclude-from两种写法

个人还是习惯将要排除同步的目录卸载单独的文件列表里,便于管理。使用--include-from=FILE时,排除文件列表用绝对路径,但FILE里面的内容请用相对路径,如:

/etc/rsyncd.d/rsync_exclude.lst:
mail/2014/
mail/201*/201*/201*/.??*
mail??*
src/*.html*
src/js/
src/ext3/
src/2014/20140[1-9]/
src/201*/201*/201*/.??*
membermail/
membermail??*
membermail/201*/201*/201*/.??*

排除同步的内容包括,mail下的2014目录,类似2015/201501/20150101/下的临时或隐藏文件等

触发脚本如下:(未加入排除选项)

#bin/bash
#rsync auto sync script with inotify
#2018-2-25 mumengyun
current_date=$(date +%Y%m%d_%H%M%S)
source_path=/data/wwwroot/sync/
log_file=/data/wwwlogs/rsync.log

#rsync
rsync_server=192.168.221.128
rsync_user=root
rsync_pwd=/etc/passwd.txt
rsync_module=Sync
#RSYNC_EXCLUDE='/etc/rsyncd.d/rsync_exclude.list'

#rsync client pwd check
if [ ! -e ${rsync_pwd} ];then
echo -e "rsync client passwod file ${rsync_pwd} does not exist!"
exit 0
fi

for ip in $rsync_server
do
/usr/bin/rsync -auvrtzopgP --port=873 --progress --delete --bwlimit=200 --password-file=${rsync_pwd} ${source_path} ${rsync_user}@$ip::${rsync_module}
done

/usr/local/inotify/bin/inotifywait -mrq --timefmt '%Y/%m/%d-%H:%M:%S' --format '%T %w %f' -e close_write,modify,delete,create,move,attrib ${source_path} | while read file
do
for ip in $rsync_server
do
/usr/bin/rsync -auvrtzopgP --port=873 --progress --delete --bwlimit=200 --password-file=${rsync_pwd} ${source_path} ${rsync_user}@$ip::${rsync_module}
done
done
#inotify log
inotify_fun >> ${log_file} 2>&1 &

--bwlimit=200用于限制传输速率最大200kb,因为在实际应用中发现如果不做速率限制,会导致巨大的CPU消耗