rsync+inotify数据实时同步
1. rsync概述
1.1 rsync简介
- rsync是可以实现增量备份的工具。配合任务计划,rsync能实现定时或间隔同步,配合inotify或sersync,可以实现触发式的实时同步。
- rsync的目的是实现两端主机之间的文件同步,所有实现的cp、rm、scp等功能只是同步的辅助手段,且rsync对于这些功能的实现方式和和本地的这些命令是不同的。
1.2 rsync同步过程的模式组成
1)决定哪些文件需要同步的检查模式
- 检查模式是按照规则来检查哪些文件需要被同步,以及哪些文件是明确被排除不传输的
- 默认情况下,rsync使用“quick check”算法快速检查源文件和目标文件的大小、mtime是否一致,如果不一致则需要传输
2)文件同步时的同步模式
- 同步模式志在文件确定要被同步后,在同步过程中发生之前要做哪些额外工作,如是否要先删除源主机上没有但目标主机上有的文件、是否要先备份已经存在的目标文件,是否要追踪链接文件等额外操作。
1.3 rsync的三种工作方式
- 单个主机本地之间的数据传输(类似于cp命令的功能)
- 借助rpc、ssh等通道来传输数据(类似于scp命令的功能)
- 本地主机通过网络套接字连接远程主机上的rsync daemon(让远程主机上运行rsync服务,使其监听在一个端口上,等待客户端的连接)
- rsync默认监听873/tcp端口
2. rsync实现数据推送&拉取&筛选
2.1 rsync本地数据传输
1)语法规则
rsync [OPTION...] SRC... [DEST] # 第一个路径参数一定是源文件路径(作为同步基准的一方),可以同时制定多个源文件路径 # 最后一个路径参数是目标文件(待同步的一方) # 路径的格式可以是本地路径,也可以是使用user@host:path或user@host::path的远程路径 # 如果主机和path路径之间使用单个冒号隔开,表示使用的是远程shell通信方式,而使用双冒号隔开的则表示的是连接rsync daemon
- 如果仅有一个SRC或DEST参数,则将以类似于"ls -l"的方式列出源文件列表(只有一个路径参数,总会认为是源文件),而不是复制文件
- 源路径如果是一个目录的话,不带尾随斜线表示的是整个目录包括目录本身,带上尾随斜线表示的是目录中的文件,不包括目录本身
[root@xuexi ~]# rsync /etc/fstab /tmp # 在本地同步 [root@xuexi ~]# rsync -r /etc 172.16.10.5:/tmp # 将本地/etc目录拷贝到远程主机的/tmp下,以保证远程/tmp目录和本地/etc保持同步 [root@xuexi ~]# rsync -r 172.16.10.5:/etc /tmp # 将远程主机的/etc目录拷贝到本地/tmp下,以保证本地/tmp目录和远程/etc保持同步 [root@xuexi ~]# rsync /etc/ # 列出本地/etc/目录下的文件列表 [root@xuexi ~]# rsync 172.16.10.5:/tmp/ # 列出远程主机上/tmp/目录下的文件列表
2)使用及参数说明
# 普通的本地文件的复制 rsync 源 目标 # 普通的本地文件复制,并保持文件的所有属性(-avz) rsync -avz 源 目标 # 参数说明 -a 以递归的方式传输数据,并保持文件的所有属性,相当于-lrtopgD -v 显示详细信息 -z 压缩传输 -r 递归模式 -t --times,保持文件时间信息 -o --owner,保持文件的属主信息 -p --perms,保持文件权限 -g --group,保持文件属组信息 -P --progress,显示同步的过程及传输时的进度等信息 -D --devices,保持设备文件信息 -l --links,保留软链接信息 # 删除/data/目录中的内容 rsync -r --delete /null/ /data/ # null目录要事先创建且为空,其实就是将data目录跟null目录同步 # 目录后面的那个斜线要加上,如果null中有内容,则会将data目录中的所有内容全部删除之后再进行同步
2.2 rsync借助ssh通道传输数据
1)借助ssh通道将数据推送到远端主机
# 将本地的/etc/hosts文件通过ssh通道推送到远程主机的家目录下 rsync -avz /etc/hosts -e "ssh -p 22 -o StrictHostKeyChecking=no" hgzero@10.0.0.202:~ # 说明: -e:表示使用ssh通道/etc/hosts 表示本地要推送的文件 wzh 表示远程主机的用户名 IP地址后面的冒号:是指定远程主机接收文件的路径
2)借助ssh通道从远端主机拉取数据
# 将远端主机的整个/opt目录拉取到本地的/tmp目录中来 rsync -avzP -e "ssh -p 22" hgzero@10.0.0.202:/opt /tmp # 说明: -P:表示显示同步的过程(--pregress)
2.3 rsync以守护进程方式传输数据
1)rsync守护进程daemon模式的配置(rsync服务端的配置)
- rsync服务的配置文件:/etc/rsync.conf
### 全局配置参数 port=888 # 指定rsync端口,默认873 uid = rsync # rsync服务的运行用户,默认是nobody,文件传输成功后属主将是这个uid gid = rsync # rsync服务的运行组,默认是nobody,文件传输成功后属组将是这个gid use chroot = no # rsync daemon在传输前是否切换到指定的path目录下,并将其监禁在内 max connections = 200 # 指定最大连接数量,0表示没有限制 timeout = 300 # 如果在这段时间内没有响应,则断开连接,以确保rsync服务器不会永远等待一个崩溃的客户端,0表示永远等待 motd file = /var/rsyncd/rsync.motd # 客户端连接过来显示的消息 pid file = /var/run/rsyncd.pid # 指定rsync daemon的pid文件 lock file = /var/run/rsync.lock # 指定锁文件,以防止多个进程同时修改一个文件产生冲突 log file = /var/log/rsyncd.log # 指定rsync的日志文件,而不把日志发送给syslog dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 # 指定哪些文件不用进行压缩传输 ### 指定模块,并设定模块配置参数,可以创建多个模块 [hgzero] # 模块ID path = /hgzero/ # 指定该模块的路径,类似于nfs的共享目录,该参数必须指定
# 启动rsync服务前该目录必须存在,rsync请求访问模块本质就是访问该路径 ignore errors # 忽略某些IO错误信息 read only = false # 指定该模块是否可读写,即能否上传文件,false表示可读写,true表示可读不可写,所有模块默认不可上传 write only = false # 指定该模式是否支持下载,设置为true表示客户端不能下载;所有模块默认可下载 list = false # 客户端请求显示模块列表时,该模块是否显示出来,设置为false则该模块为隐藏模块。默认true hosts allow = 10.0.0.0/24 # 指定允许连接到该模块的机器,多个ip用空格隔开或者设置区间 hosts deny = 0.0.0.0/32 # 指定不允许连接到该模块的机器
auth users = rsync_backup # 指定连接到该模块的用户列表,只有列表里的用户才能连接到模块,用户名和对应密码保存在secrts file中, # 这里使用的不是系统用户,而是虚拟用户,不设置时,默认所有用户都能连接,但使用的是匿名连接 secrets file = /etc/rsyncd.passwd # 保存auth users用户列表的用户名和密码,每行包含一个username:passwd
# 由于"strict modes"默认为true,所以此文件要求非rsync daemon用户不可读写
# 只有启用了auth users该选项才有效
# 定义第二个模块
[shit] path=/shit/ read only = false ignore errors comment = anyone can access
- 服务端中rsync服务的启动及后续操作
rsync --daemon # 启动rsync服务,然后再用lsof -i :873检查一下 useradd rsync -s /sbin/nologin # 添加一个虚拟用户 chown -R rsync.rsync /hgzero # 对共享目录进行授权 echo "rsync_backup:woshiniba" > /etc/rsyncd.passwd # 将用户名和密码添加到文件中,rsync_backup是rsync的虚拟用户名,密码是woshiniba chomd 600 /etc/rsyncd.passwd # 降低密码文件的权限,因为密码是明文的,所以设置600是为了防止其他用户看到密码 # 关闭防火墙 # 关闭SELinux
2)rsync守护进程daemon模式的配置(rsync客户端的配置)
echo "woshiniba" > /etc/rsyncd.passwd # 只在密码文件中添加密码,以避免交互式的输入密码 chmod 600 /etc/rsyncd.passwd # 设置密码文件的权限
3)在Client端进行数据的拉取或推送
- 在client端实现对server端数据的拉取
# 从hgzero模块中指定的文件路径中将数据拉取到client端的/data目录下
rsync -avz rsync_backup@10.0.0.101::hgzero /data # rsync_backup代表的是登录的用户 # :: 后面的hgzero表示的配置文件中指定的模块hgzero中对应的path共享路径 # 按照以上配置之后拉取的时候需要手动输入密码,可以添加--password-file参数以自动输入密码
rsync -avz rsync_backup@10.0.0.101::hgzero /data --password-file=/etc/rsync.password - 在client端将数据推送到server端
# 将本地的/data/目录下的内容推送到远端hgzero模块对应的路径中 rsync -avz /data/ rsync_backup@10.0.0.101::hgzero --password-file=/etc/rsync.password # 注意:这里的data一定要写全路径并加上全双下划线,如果这里的hgzero不写的话,默认将推送到指定配置文件的目录中
- 另外一种数据拉取和推送的方式
# 1. client端从服务端拉取数据: rsync -avz rsync://rsync_backup@10.0.0.101/hgzero/ /data --password-file=/etc/rsync.password # 这里的rsync://是固定写法,后面的hgzer指的是配置文件中指定的目录,可以在这里后接,如 /hgzero/wzh/hg # 2. client端将数据推送到服务端: rsync -avz /data/ rsync://rsync_backup@10.0.0.101/hgzero/ --password-file=/etc/rsync.password
2.4 对传输的文件进行筛选(排除)
1)在客户端的排除
# 描述: --exclude=PATTERN exclude files matching PATTERN # 以指定的样式进行排除 --exclude-from=FILE read exclude patterns from FILE # 以文件中指定的样式进行排除 # 操作: rsync -avz --exclude=a /data/ rsync_backup@10.0.0.101::hgzero --password-file=/etc/rsync.password # 效果:要传输的文件除了文件名为a的文件 # 注意:如果要排除多个文件,则可以使用这样的形式:--exclude={a,b,c,d} 传输除了a,b,c,d之外的其他所有文件,或者再写几个--exclude rsync -avz --exclude-from=paichu.log /data/ rsync_backup@10.0.0.101::hgzero --password-file=/etc/rsync.password # 效果:在paichu.log这个文件中定义了所有要排除的文件名的pattern样式 # 注意:这里要先创建paichu.log文件,并在其中定义要排除的文件名的样式
2)在服务端的排除
# 1. 在配置文件 /etc/rsyncd.conf 中添加:exclude = a b c (注意这里是以空格隔开) # 2. 杀死rsync进程 kill cat `/var/run/rsyncd.pid` pkill rsync # 3. 启动rsync服务 rsync --daemon # 4. 查看 ps -ef | grep rsync # 注意:因为在服务端配置灵活性差,且维护麻烦,所以一般不在服务端进行排除的配置
2.5 无差异同步
1)--delete选项(实现无差异同步)
- 要实现无差异同步,只需在服务端加上--delete参数即可实现
- 使用--delete选项后,接收端的rsync会先删除目标目录下已经存在,但源端目录不存在的文件(多则删除,少则补充)
2)无差异同步的风险
- rsync推送:备份
- --delete风险:本地有什么,远端就有什么,本地没有的,远端也要删除,服务端的目录数据可能丢失
- rsync拉取:代码发布、下载
- --delete风险:远端有什么,本地(客户端)就有什么,远端没有的,本地也要删除,本地的目录数据可能丢失
3)无差异同步的应用场景
一般是需要两台服务器之间,必须要求数据一致,且实时性又不是很高的情况;如两台负载均衡下面web服务器之间的同步,或者高可用双机配置之间的同步等。
rsync无差异同步非常的危险,而且,有很多的替代方案,因此,生产场景如果没有特殊的需求,应该尽量避免使用。
2.6 rsync服务共享多个目录的配置
- 思路:将多个模块中共有的内容统一放到全局配置,然后在每个模块中写其特有的功能效果
- 在多目录的共享中要注意用户对该共享目录的权限
uid = rsync gid = rsync use chroot = no max connections = 200 timeout = 300 pid file = /var/run/rsyncd.pid lock file = /var/run/rsyncd.lock log file = /var/log/rsync.log ignore errors read only = false list = false hosts allow = 10.0.0.0/24 hosts deny = 0.0.0.0/32 auth users = rsync_backup secrets file = /etc/rsync.password
[hgzero] path = /hgzero/ [data] path = /data/
3. rsync实战案例
3.1 rsync备份脚本
#!/bin/sh ip=$(ifconfig ens33 | awk 'NR==2{print $2}') # 获取本机ip地址 [ ! -d /backup/$ip ] && mkdir -p /backup/$ip # 判断是否有备份文件集中的目录,如果没有则创建 cd /backup/$ip &&\ # 进入这个目录后对要备份的文件进行打包 tar -zcf bak_$(date +%F).tar.gz /var/www/html /app/logs/access_$(date +%F -d -1day).log /server/scripts/ /var/spool/cron # 利用rsync将这些打包好的文件传送到备份服务器上 rsync -az /backup/ rsync_backup@10.0.0.101::backup/ --password-file=/etc/rsync.password # 删除备份集中目录中7天以前的文件 find /backup -type f -name "*.tar.gz" -mtime +7 | xargs rm -f
- 然后将以上脚本保存到 /server/script 中,添加到定时任务中就ok了
- 如果是100台服务器需要备份,则将这100台服务器都作为rsync的客户端就ok了,定时执行以上脚本
3.2 备份结果信息通知
1)问题及解决思路
- 问题:在备份数据后,需要把备份的成功以及失败的结果信息发送到系统管理员的邮箱中
- 思路:需要在服务器端检查,而不是客户端直接将信息发送给管理员
2)实现方式
- 先查看backup目录的大小,并写入记录,然后进行对比大写和修改时间来判断成功或失败
- 然后对文件进行打包、推送,再推送一个flag(ip+时间的文件名),本地清理7天以前的
- 加上一个flag标记在以上执行脚本bak.sh中rsync语句的后面
rsync -az /backup/ rsync_backup@10.0.0.101::backup/ --password-file=/etc/rsync.password && touch ${ip}_flag_$(date +%F) # 表示如果rsync推送成功,就在本地创建一个flag文件来做标记 # 但是这个标记文件并没有在rsync推送的时候一起推送过去,因为它的执行是在rsync之后,所以还需要来一次rsync推送来把这个标记文件也推送过去
# 这时,如果在服务端看到这个标记文件,并且日期也对,则表示推送成功 # 这是一种检查的思想
- 加上一个flag标记在以上执行脚本bak.sh中rsync语句的后面
- 手工或定时的解包,模拟数据恢复来确定数据备份的完整性
3.3 全网数据备份解决方案
- 先做好数据同步rsync服务(备份服务器上部署rsync服务)
- 本地打包备份脚本实现(webserver以及其他需要备份的机器上)
- 配置定时任务执行脚本
- 整体测试成功
3.4 配置实时数据同步架构
- 做好数据同步rsync服务(backup server上部署rsync服务)
- 配置inotify服务,或者配置sersync服务(在客户端web服务器上配置)
- 开发同步脚本,测试检查同步情况
- 压力测试,查看并发是多少可以实时同步
- 后台运行同步脚本,并且设置开机自启动(放入rc.local中)
4. inotify详解
4.1 inotify概述
- 在客户端将rsync加入定时任务,可以实现定时同步数据,但是定时任务的同步时间粒度不能达到实时同步的要求,进而引入inotify
- inotify是一种异步的文件系统事件监控机制软件,inotify是建立在rsync服务基础上进行配置的
- 客户端通过inotify进行获取到目录内的变化,然后通知执行rsync命令同步数据
- inotify的实现软件:inotify、sersync、lsyncd
4.2 inotify的安装
1)检查rsync服务是否正常运行,且是否可以进行数据的推送或拉取
[root@c7_node_04 hg]# ps -ef |grep rsync
root 19698 1 0 15:50 ? 00:00:00 rsync --daemon
2)检查系统内核版本及文件检查
[root@c7_node_05 rsync_test]# ll /proc/sys/fs/inotify/ total 0 -rw-r--r-- 1 root root 0 Sep 17 17:02 max_queued_events -rw-r--r-- 1 root root 0 Sep 17 17:02 max_user_instances -rw-r--r-- 1 root root 0 Sep 17 17:02 max_user_watches
- 必须要有以下的这三个文件才可以继续以下操作
- max_queued_events 表示最大的监控队列 , 这个值最好要调大一点(一般设置30万左右)
- max_user_instances 表示用户的实例
- max_user_watches 生产环境一般设置成5千万
3)编译安装inotify工具
- 先要安装好编译环境(如gcc编译工具等)
tar xf inotify-tools-3.14.tar.gz ./configure --prefix=/usr/local/inotify-tools-3.14 make && make install ln -s /usr/local/inotify-tools-3.14 /usr/local/inotify
4)inotify的安装位置说明
- inotify是监控工具,监控目录或文件的变化,然后触发一系列的操作。
- 假如有一台站点发布服务器A,还有3台web服务器B/C/D,目的是让服务器A上存放站点的目录中有文件变化时,自动触发同步将它们推到web服务器上,这样能够让web服务器最快的获取到最新的文件。
- 监控的是A上的目录,推送到的是B/C/D服务器,所以在站点发布服务器A上装好inotify工具。
- 一般还在web服务器BCD上将rsync配置为daemon运行模式,让其在873端口上处于监听状态(并非必须,即使是sersync也非必须如此)。
- 对于rsync来说,监控端是rsync的客户端,其他的是rsync的服务端,但并非一定需要如此。
- inotify是独立的工具,它和rsync无关,它只是为rsync提供一种比较好的实时同步方式而已。
4.3 inotify-tools使用说明
1)inotify-tools软件结构
- /usr/bin/inotifywait
- 实时监控文件目录的实时事件,等待文件发生变化
- /usr/bin/inotifywatch
- 用于统计文件系统的事件
2)inotifywait使用参数(实时监控文件目录中的所有事件)
-r ,--recursive # 递归查询目录 -q ,--quite # 打印很少的信息,仅打印事件信息 -m ,--monitor # 始终保持事件监听状态,否则应该是监控到了一次就退出监控了 --exclude <pattern> # 通过模式匹配来指定不被监控的文件,区分大小写 --excludei <pattern> # 通过模式匹配来指定不被监控的文件,并不区分大小写 --timefmt # 指定时间输出的格式 --format # 打印使用指定的输出类似格式字符串,如[--format '%w%f %e%T'] %w:产生事件的监控路径,不一定就是发生事件的具体文件,例如递归监控一个目录,该目录下的某文件产生事件,将输出该目录而非其内具体的文件 %f:如果监控的是一个目录,则输出产生事件的具体文件名。其他所有情况都输出空字符串 %e:产生的事件名称 %T:以"--timefmt"定义的时间格式输出当前时间,要求同时定义"--timefmt" -e # 通过此参数可以指定需要监控的事件: access 文件或目录被读取 modify 文件或目录被修改 attrib 元数据被修改,包括权限、时间戳、扩展属性等 close 文件或目录封闭,无论读还是写模式 close_write 文件或目录在写入模式之后被关闭
close_nowrite只读模式下文件被关闭,即只能是为了读取而打开文件,读取结束后关闭文件的事件 open 文件或目录被打开 moved_to 文件或目录被移动至另外一个目录
moved_from 将监控目录下文件或目录移动到其他地方,也可以是在监控目录内部的移动 move 文件或目录被移动到另一个目录或从另一个目录移动到当前目录,是moved_to和moved_from的结合 create 文件或目录被创建在当前目录 delete 文件或目录被删除 umount 挂载在被监控目录上的文件系统被umount,umount后不再监控此目录
isdir 监控目录相关操作
4.4 inotify监听实例
/usr/local/inotify-tools-3.14/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f' -e create /data # 当/data/目录中有新的内容被创建时,就会产生反馈(以指定的样式来打印时间和文件名) /usr/local/inotify-tools-3.14/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f' -e create,delete /data # 当/data/目录中有内容被创建和删除时,就会产生反馈
- inotify进行实时同步生产环境中的最大文件数量是200到300个,大小是10到500k,若超过这个数字就会有延迟
4.5 rsync+inotify实时同步脚本
- 关于rsync+inotify的缺陷
- inotify需要解决的问题在于需要尽量少的来触发事件,以尽量减少重复触发rsync
1)rsync+inotify的简单实现
#!/bin/sh cmd="/usr/local/inotify/bin/inotifywait" $cmd -mrq --format '%w%f' -e create,close_write,delete /backup|\ while read line do [! -e "$line" ] && continue rsync -az --delete $line rsync_backup@10.0.0.2::hgzero --password-file=/etc/rsync.password done
2)rsync+inotify的最佳实现
#!/bin/bash watch_dir=/www push_to=172.16.10.5 # First to do is initial sync rsync -az --delete --exclude="*.swp" --exclude="*.swx" $watch_dir $push_to:/tmp inotifywait -mrq -e delete,close_write,moved_to,moved_from,isdir --timefmt '%Y-%m-%d %H:%M:%S' --format '%w%f:%e:%T' $watch_dir \ --exclude=".*.swp" >>/etc/inotifywait.log & while true;do if [ -s "/etc/inotifywait.log" ];then grep -i -E "delete|moved_from" /etc/inotifywait.log >> /etc/inotify_away.log rsync -az --delete --exclude="*.swp" --exclude="*.swx" $watch_dir $push_to:/tmp if [ $? -ne 0 ];then echo "$watch_dir sync to $push_to failed at `date +"%F %T"`,please check it by manual" |\ mail -s "inotify+Rsync error has occurred" root@localhost fi cat /dev/null > /etc/inotifywait.log rsync -az --delete --exclude="*.swp" --exclude="*.swx" $watch_dir $push_to:/tmp else sleep 1 fi done
- 相关链接: