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)实现方式

  1. 先查看backup目录的大小,并写入记录,然后进行对比大写和修改时间来判断成功或失败
  2. 然后对文件进行打包、推送,再推送一个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推送来把这个标记文件也推送过去
      # 这时,如果在服务端看到这个标记文件,并且日期也对,则表示推送成功
      # 这是一种检查的思想
  3. 手工或定时的解包,模拟数据恢复来确定数据备份的完整性

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实时同步脚本

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
原文地址:https://www.cnblogs.com/hgzero/p/13684442.html