通过rsync+inotify实现实时数据同步

rsync(Remote Sync)是一个开源的快速备份工具,可以在不同主机之间镜像同步整个目录树,支持增量备份,并保持链接和权限,且采用优化的同步算法,传输前执行压缩,因此非常使用与异地备份、镜像服务器等应用。在远程同步任务重,负责发起rsync同步操作的客户机称为发起端,二负责响应来自客户机的rsync同步操作的服务器称为同步源。在同步过程中,同步源负责提供文件的原始位置,发起端应对该位置具有读取权限。
- 支持本地复制,或者与其他SSH、rsync 主机同步
- 官方网站:https://rsync.samba.org/

命令参数
常用参数
| 参数 | 说明 |
|---|---|
| -v | verbose 详细输出 |
| -a | 归档模式,递归方式传输文件,并保持连接,权限,用户和组,时间信息 |
| -z | 压缩文件传输 |
| -h | human-readable, 输出友好 |
| -u | 跳过已经存在的文件,备份更新 |
| -r | –recursive 对子目录以递归模式处理 |
| –delete | 删除那些 DST 中 SRC 没有的文件 |
| -p | –perms 保持文件权限 |
所有参数
| 参数 | 说明 |
|---|---|
| -v | –verbose 详细模式输出 |
| -q | –quiet 精简输出模式 |
| -c | –checksum 根据校验和(而不是文件大小、修改时间)来决定是否跳过文件 |
| -a | –archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于 -rlptgoD |
| -r | –recursive 对子目录以递归模式处理 |
| -R | –relative 使用相对路径信息 |
| -b | –backup 创建备份,也就是对于目的已经存在有同样的文件名时,将老的文件重新命名为~filename。可以使用 –suffix 选项来指定不同的备份文件前缀。 |
| –backup-dir | 将备份文件(如~filename) 存放在在目录下。 |
| -suffix=SUFFIX | 定义备份文件前缀 |
| -u | –update 仅仅进行更新,也就是跳过所有已经存在于 DST,并且文件时间晚于要备份的文件。(不覆盖更新的文件) |
| -l | –links 保留软链结 |
| -L | –copy-links 想对待常规文件一样处理软链结 |
| –copy-unsafe-links | 仅仅拷贝指向 SRC 路径目录树以外的链结 |
| –safe-links | 忽略指向 SRC 路径目录树以外的链结 |
| -H | –hard-links 保留硬链结 |
| -p | –perms 保持文件权限 |
| -o | –owner 保持文件属主信息 |
| -g | –group 保持文件属组信息 |
| -D | –devices 保持设备文件信息 |
| -t | –times 保持文件时间信息 |
| -S | –sparse 对稀疏文件进行特殊处理以节省 DST 的空间 |
| -n | –dry-run 现实哪些文件将被传输 |
| -W | –whole-file 拷贝文件,不进行增量检测 |
| -x | –one-file-system 不要跨越文件系统边界 |
| -B | –block-size=SIZE 检验算法使用的块尺寸,默认是 700 字节 |
| -e | –rsh=COMMAND 指定使用 rsh、ssh 方式进行数据同步 |
| –rsync-path=PATH | 指定远程服务器上的 rsync 命令所在路径信息 |
| -C | –cvs-exclude 使用和 CVS 一样的方法自动忽略文件,用来排除那些不希望传输的文件 |
| –existing | 仅仅更新那些已经存在于 DST 的文件,而不备份那些新创建的文件 |
| –delete | 删除那些 DST 中 SRC 没有的文件 |
| –delete-excluded | 同样删除接收端那些被该选项指定排除的文件 |
| –delete-after | 传输结束以后再删除 |
| –ignore-errors | 及时出现 IO 错误也进行删除 |
| –max-delete=NUM | 最多删除 NUM 个文件 |
| –partial | 保留那些因故没有完全传输的文件,以是加快随后的再次传输 |
| –force | 强制删除目录,即使不为空 |
| –numeric-ids | 不将数字的用户和组 ID 匹配为用户名和组名 |
| –timeout=TIME IP | 超时时间,单位为秒 |
| -I | –ignore-times 不跳过那些有同样的时间和长度的文件 |
| –size-only | 当决定是否要备份文件时,仅仅察看文件大小而不考虑文件时间 |
| –modify-window=NUM | 决定文件是否时间相同时使用的时间戳窗口,默认为 0 |
| -T –temp-dir=DIR | 在 DIR 中创建临时文件 |
| –compare-dest=DIR | 同样比较 DIR 中的文件来决定是否需要备份 |
| -P | 等同于 –partial |
| –progress | 显示备份过程 |
| -z | –compress 对备份的文件在传输时进行压缩处理 |
| –exclude=PATTERN | 指定排除不需要传输的文件模式 |
| –include=PATTERN | 指定不排除而需要传输的文件模式 |
| –exclude-from=FILE | 排除 FILE 中指定模式的文件 |
| –include-from=FILE | 不排除 FILE 指定模式匹配的文件 |
| –version | 打印版本信息 |
安装
服务端(同步源)
- 安装rsync
[root@openresty-dev ~]# dnf -y install rsync
- 创建用户
[root@openresty-dev ~]# useradd rsync -s /sbin/nologin
- 创建同步目录
[root@openresty-dev ~]# mkdir /data/webfile
[root@openresty-dev ~]# chown -R rsync:rsync /data/webfile
- 修改配置文件
[root@openresty-dev ~]# vim /etc/rsyncd.conf
# RSYNC Config
# 指定传输文件使用的用户
uid = rsync
# 指定传输文件使用的用户组
gid = rsync
# 安全设置,切换到安全目录
use chroot = yes
# 最大连接数
max connections = 10
# 客户端超时时间,单位秒,设置为 0 不超时
timeout = 900
# PID 文件
pid file = /var/run/rsyncd.pid
# 锁文件
lock file = /var/run/rsync.lock
# 日志文件
log file = /var/log/rsyncd.log
# 日志记录方式
transfer logging = yes
# 忽略文件
exclude = lost+found/
# 忽略不可读文件
ignore nonreadable = yes
# 传输时不压缩的文件
dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2
# 现在的版本需要添加,保留文件的完整属性
fake super = yes
# 模块
[data]
# 对应的目录
path = /data/webfile
# 传输的删除时忽略 I/O 错误,报错会跳过--delete
ignore errors
# 允许写入
read only = false
# 不允许列出
list = false
# 允许的网段,多个使用空格隔开
hosts allow = 192.168.3.0/24
# 拒绝的网段,拒绝所有
hosts deny = 0.0.0.0/32
# 连接的虚拟用户,非系统用户
auth users = rsuser
# 虚拟用户的账号密码文件
secrets file = /etc/rsuser.password
# 注释说明
comment = Test file share
- 创建密码文件
[root@openresty-dev ~]# echo "ruser:123456" > /etc/rsuser.password
[root@openresty-dev ~]# chmod 600 /etc/rsuser.password
- 启动服务
[root@openresty-dev ~]# rsync --daemon
[root@openresty-dev ~]# ss -tlunp | grep 873
[root@openresty-dev data]# ss -anptu | grep 873
tcp LISTEN 0 5 0.0.0.0:873 0.0.0.0:* users:(("rsync",pid=4193,fd=5))
tcp LISTEN 0 5 [::]:873 [::]:* users:(("rsync",pid=4193,fd=6))
客户端(被同步端)
- 安装rsync
[root@docker ~]# dnf -y install rsync
- 创建密码验证文件
# 注意客户端上面的密码文件中,不需要写用户名,直接写密码就可以了。
[root@docker ~]# echo "123456" > /etc/rsuser.password
[root@docker ~]# chmod 600 /etc/rsuser.password
- 测试同步
# 同步远程文件到本地 (Pull)
root@docker ~]# rsync -av --password-file=/etc/rsuser.password rsuser@192.168.3.19::data /data/webfile
receiving incremental file list
created directory /data/webfile
./
1.txt
sent 50 bytes received 121 bytes 342.00 bytes/sec
total size is 0 speedup is 0.00
# 同步本地文件到远端 (Push)
[root@docker ~]# rsync -arvz --password-file=/etc/rsuser.password docker.svr.test rsuser@192.168.3.19::data
sending incremental file list
docker.svr.test
sent 109 bytes received 43 bytes 101.33 bytes/sec
total size is 0 speedup is 0.00
inotify 介绍及应用
inotify 是一种强大的、细粒度的、异步文件系统监控机制,内置于Linux内核 2.6.13 及以上版本。为了使用这一内核功能,用户需要配合相应的工具,通常需要用户空间的软件调用才能实现,实现inotify软件有inotify-tools、sersync、lrsyncd。
inotify-tools 是实现 inotify 的一个常用软件包,主要包含两个工具:
- inotifywait:用于在被监控的文件或目录上等待特定文件系统事件(如打开、关闭、删除等)发生,常用于实时同步的目录监控。
- inotifywatch:用于收集被监控的文件系统的统计数据,指文件系统事件发生次数的统计。
在使用 inotify-tools 时,首先需要开启 inotify 进程,该进程将实时监控目标目录的变化情况,并根据设置通过 rsync 命令立即同步至服务器。要实现 inotify 的实时监控,必须先成功配置并验证 rsync 服务的推送功能。
安装
[root@docker ~]# dnf install -y inotify-tools
内核调优
[root@docker ~]# vim /etc/sysctl.conf #添加以下代码
fs.inotify.max_queued_events = 16384
# 监控事件队列;
# 表示调用inotify_init时分配给instance中可排队的
# event的数目的最大值,超出这个值的事件被丢弃,但会
# 触发IN_Q_OVERFLOW事件
fs.inotify.max_user_instances = 128
# 最多监控实例数;
# 表示每一个真实用户ID可创建的instatnces的数量上限
fs.inotify.max_user_watches = 524288
# 每个实例最多监控目录数;
# 表示每个instatnces可监控的最大目录数量,如果监控
# 的文件数目巨大,需要根据情况,适当增加此值的大小
触发脚本
[root@docker ~]# vim inotify.sh
#!/bin/sh
srcdir=/data/webfile
dstdir=/data/webfile
rsyncuser=rsuser
rsyncpassdir=/etc/rsuser.password
dstip="192.168.3.19"
for ip in $dstip
do
rsync -avH --port=873 --progress --delete $srcdir $rsyncuser@$ip::$dstdir --password-file=$rsyncpassdir
done
/usr/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f%e' -e close_write,modify,delete,create,attrib,move $srcdir | while read file
do
for ip in $dstip
do
rsync -avH --port=873 --progress --delete $srcdir $rsyncuser@$ip::$dstdir --password-file=$rsyncpassdir
echo " ${file} was rsynced" >> /tmp/rsync.log 2>&1
done
done
[root@docker ~]# chmod a+x inotify.sh
[root@docker ~]# nohup inotify.sh &