首页 > 技术分享 > Other
收藏

rsync和inotify实现静态资源自动化同步方案

06/25 20:51
大潇博客 原创文章,转载请标明出处

本文目录


1、了解rsync以及同步技术

在 Linux 系统中,同步两台及多台服务器的静态文件,有多方式可以实现,比如常用的 rcp 命令,这里介绍一个比较成熟的工具 rsync。

rsync 是一个远程数据同步工具,可通过 lan/wan 快速同步多台主机之间的文件,也可以使用 rsync 同步本地硬盘中的不同目录。它可以监控当前目录下所有文件的变动,然后使用所谓的 rsync 算法进行数据同步,这种算法只传递两个文件的不同部分,而不是每次都整份传递,因此速度相当快。

rsync 主要所用:比对、推送、复制。它有远程比对的过程,如果只有一个文件发生变化,就只推一个文件过去,并且在传输的时候,完成了压缩工作。


2、安装与配置rsync

2.1 安装rsync

查看系统源是否存在 rsync,存在就可以直接安装,不存在需要下载 rsync 后编辑安装,以 Debian 为例:

注意:远程服务器和本地服务器都需要安装 rsync,只有单台服务器安装了 rsync,无法进行连接

apt update

apt list rsync*

apt install rsync


2.2 启动rsync

rsync --daemon

如果报错:

说明缺失配置文件,启动 rsync 时 /etc 目录下必须要有配置文件 rsyncd.conf (文件为空也能启动,只要存在即可)

使用 apt 安装的 rsync,配置文件默认位置:/usr/share/doc/rsync/examples/rsyncd.conf,可将此文件复制到 /etc/rsyncd.conf,命令:

cp /usr/share/doc/rsync/examples/rsyncd.conf /etc/rsyncd.conf

默认的配置文件中包含一些配置信息,比如:默认资源名为 ftp,查看或者同步文件时使用 ftp 即可,也可通过配置文件修改资源名。


2.3 设定rsync开机自启动

① 设置自启 rsync 服务

systemctl enable rsync

② 将 rsync 设置为守护进程,编辑配置文件

nano /etc/default/rsync

将 RSYNC_ENABLE 的值设置为 true

# 控制 rsync 守护进程(rsyncd) 是否作为系统服务开机自启并保持后台运行

# 设为 true 表示将此主机作为 rsync 服务器,监听 873 端口,远程客户端来拉取或推送文件(作为服务器端)

# 设为 false 表示禁用该服务,此主机仅可作为 rsync 客户端使用

RSYNC_ENABLE=true


3、未增加认证时的基础操作

3.1 查看远程服务器文件

rsync --list-only 远程IP地址::资源名/

比如:

rsync --list-only 10.168.1.150::ftp/

如果提示错误:rsync error: error starting client-server protocol (code 5) at main. (1863),如下:

查看配置文件中的 path,默认的 path 是 /var/path/pub,将 path 修改为实际项目的地址

修改后需要重启 rsync 

pkill -9 -x rsync; sleep 1; rsync --daemon


3.2 本地同步远程文件

rsync -avz --delete 远程IP地址::资源名/ 本地存放目录

比如

rsync -avz --delete 10.168.1.150::ftp/ /www/swoole

rsync常用指令:


4、增加安全认证并进行远程操作

4.1 远程服务器增加安全认证

① 设置用户和密码(需要创建密码文件):

在远程服务器中创建 /etc/rsyncd.pwd 文件,文件内容仅为“用户名:密码”

echo "dx:168" >> /etc/rsyncd.pwd

② 编辑远程服务器配置文件:

nano /etc/rsyncd.conf

修改以下配置项配(可在全局中添加,也可以修改单个资源下的配置):

注意:账号密码是虚拟的,仅 rsync 软件使用,操作系统中并没有在真实存在。配置文件中若不存在这两项,添加即可。

auth users = dx #设置授权用户

secrets file = /etc/rsyncd.pwd #设置密码文件地址

③ 保存后重启 rsync,rsync 没有重启命令,重启方式为 kill 进程后重新运行。

pkill -9 -x rsync; sleep 1; rsync --daemon


4.2 本地服务器,通过用户密码连接远程服务器

远程服务器设置了用户和密码后,每次连接都需要携带用户信息:

rsync --list-only 用户名@IP地址::资源名/

比如:

rsync --list-only dx@10.168.1.150::ftp/

输入上面的命令后,再根据提示输入密码即可连接成功。若远程连接时有如下提示:

这说明远程服务器的密码文件权限过高,有被篡改的风险,需要修改密码文件权限(降权):

chmod 600 /etc/rsyncd.pwd

修改后重启 rsync

pkill -9 -x rsync; sleep 1; rsync --daemon

小提示:由于 rsync 是后台运行,启动时出现错误可能不会在终端展示,所以会出现连接时 rsync 虽报了错,却不能及时看到错误提示。所以如果发现用户名 + 密码连接不上,先查看密码文件权限(权限不能设置太高)。


5、设置免密登录

① 远程服务器设置了用户密码后,本地服务器也需要创建密码文件,内容仅为密码:

echo "111" >> /etc/rsyncd.pwd.client

② 修改权限(降权):

本地的密码文件类似远程服务器的密码文件,同样需要降权,如果不降权,连接远程服务器时会报错,提示需要修改密码文件的权限。

chmod 600 /etc/rsyncd.pwd.client

③ 查看远程服务器文件列表:

rsync --list-only --password-file=密码文件地址 用户名@IP地址::资源名/

比如:

rsync --list-only --password-file=/etc/rsyncd.pwd.client dx@10.168.1.150::ftp/

注意:每次创建密码文件时,一定要修改权限。

同步更新/删除文件,命令:

rsync -avz -delete --password-file=/etc/rsyncd.pwd.client dx@10.168.1.150::ftp/ /www/swoole


6、推送方案

6.1 近时推送方案:

上面所讲的步骤:从本地服务器获取远程服务器的文件信息,也就是近时推送方案的雏形。

在本地服务器中制作一个脚本(或安排一个频繁运行的 cron 任务),定时发送网络请求,查询远程服务器目标目录的文件是否有变化,如果发生变化,拉取变化的文件到本地进行更新。

这样做的弊端是,即使远程服务器文件长时间没有变化,但在这期间网络请求依然在不停发送,这样繁忙的轮询,消耗大量资源并且具有不确定性,并不是很理想。


6.2 实时推送方案:

远程服务器主动连接本地服务器,如果文件发生变化,远程服务器将文件推送给本地服务器。想要实现推送的动作,每个服务器都要启动 rsync 进程(建议配置用户和密码)。


6.3 实时推送命令

推送命令有多种写法,这里举例说两种。

① 类似上文提到的拉取命令,仅把远程服务器地址和本地服务器地址互换位置,这种方式传输时不使用 rsync 协议。

在远程服务器中使用如下命令:

rsync -avz --password-file=本地密码文件地址(只有密码,非远程服务器的“账号:密码”)本地文件地址 用户名@目标服务器IP地址::资源名/

比如:

rsync -avz --delete --password-file=/etc/rsyncd.pwd.client /www/swoole/ dx@10.168.1.203::ftp/

② 通过 rsync 协议推送:

rsync -avz --password-file=/etc/rsyncd.ftp.client /www/swoole/ rsync://dx@10.168.1.203:/ftp


6.4 推送时可能遇到的错误

① 默认情况下,本地服务器接受提交过来的文件,有一定风险,所以会拒绝并报错:ERROR: module is read only

这时需要修改本地服务器的 read only 配置,打开 rsync 的配置文件,找到 read only 并把它改为 read only=no,如果没有 read only 这一项,添加到配置文件中即可。

nano /etc/rsyncd.conf

② 如果远程服务器推送执行完成后,提示这种错误:

这是因为本地服务器的 rsync 权限不足,经测试将本地服务器的目标文件夹及子目录设置为 777,依然会提示这种错误。所以建议使用如下方法:

打开本地服务器 rsync 的配置文件,将 uid 和 gid 改为 root,如果配置文件中没有这两项,添加即可。

nano /etc/rsyncd.conf

uid = root

gid = root


7、rsync 配置文件参考

# sample rsyncd.conf configuration file

uid = root

gid = root

# GLOBAL OPTIONS

# motd file=/etc/motd

# log file=/var/log/rsyncd

# for pid file, do not use /var/run/rsync.pid if

# you are going to run rsync out of the init.d script.

# The init.d script does its own pid file handling,

# so omit the "pid file" line completely in that case.

# pid file=/var/run/rsyncd.pid

# syslog facility=daemon

# socket options=

# MODULE OPTIONS

# 增加授权用户

# auth users = dx

# 增加密码文件地址

# secrets file = /etc/rsyncd.pwd


[ftp]

# comment = public archive

path = /www/swoole

# use chroot = yes

# max connections=10

# lock file = /var/lock/rsyncd

# the default for read only is yes...

# read only = yes

# list = yes

# uid = nobody

# gid = nogroup

# exclude =

# exclude from =

# include =

# include from =

auth users = dx

secrets file = /etc/rsyncd.ftp.secrets

# read only = no

# strict modes = yes

# hosts allow =

# hosts deny =

# ignore errors = no

# ignore nonreadable = yes

# transfer logging = no

# log format = %t: host %h (%a) %o %f (%l bytes). Total %b bytes.

# timeout = 600

# refuse options = checksum dry-run

# dont compress = *.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz


8、inotify监控目录变化

8.1 安装inotify

inotify 可以监控文件系统的读写删等操作,所以用它监测某个目录内的文件有无变化,如果发生变化,调用 rsync 命令,同步两台服务器的数据。

inotify 不是系统内置进程,需要先安装,如果 apt 源中没有,也可以编译安装

apt install inotify-tool

安装成功后,使用 inotifywait 监控,查找 inotifywait 程序的位置,编译安装的 inofity 在 bin 目录下,使用 apt 安装的位置是:/usr/bin/inotifywait


8.2 inotifywait使用

语法:inotifywait [-hcmrq] [-e ] [-t ] [–format ] [–timefmt ] [ … ]

-m:一直监控指定的目录(始终保持监听状态),接收到一个事情而不退出,无限期地执行。默认的行为是接收到一个事情后立即退出。

@:排除不需要监视的文件,可以是相对路径,也可以是绝对路径。

-o, –outfile:输出事情到一个文件而不是标准输出。

-s, –syslog:输出错误信息到系统日志

-d, –daemon:跟–monitor一样,除了是在后台运行,需要指定–outfile把事情输出到一个文件。也意味着使用了–syslog。

–exclude:正则匹配需要排除的文件,大小写敏感。

–excludei:正则匹配需要排除的文件,忽略大小写。

-t , –timeout:设置超时时间,如果为0,则无限期地执行下去。

-r:递归监控所监控目录的子目录。

-q:仅打印监控事件信息,指定一次,不会输出详细信息,指定二次,除了致命错误,不会输出任何信息。

–timefmt:指定时间格式。

–format:

  • %w:表示发生事件的目录
  • %f:表示发生事件的文件
  • %e:表示发生的事件
  • %Xe:事件以“X”分隔
  • %T:使用由–timefmt定义的时间格式

-e:指定监控事件项,有以下操作

  • access:文件或目录内容被读取。
  • modify:文件或目录内容被修改。
  • attrib:文件或目录属性改变。
  • close_write:文件或目录以可写模式打开后关闭。
  • close_nowrite:文件或目录以只读模式打开后关闭。
  • close:文件或目录关闭(无论读写模式)。
  • open:文件或目录被打开。
  • moved_to:文件或目录移动到监控目录。
  • moved_from:文件或目录从监控目录移出。
  • move:文件或目录在监控目录中移动。
  • create:在监控目录中创建文件或目录。
  • delete:在监控目录中删除文件或目录。
  • delete_self:文件或目录本身被删除。
  • unmount:文件系统被卸载。

常用的为以下几项


8.3 监测目录变化的命令(参考)

/usr/bin/inotifywait -mrq --timefmt '%Y-%m-%d %H:%M:%S' --format '%T %w%f %e' -e close_write,modify,delete,create,attrib,move /www/swoole/


9、rsync+inotify做自动化同步

9.1 创建自动同步脚本

① 创建脚本文件

nano /usr/local/bin/inotify_rsync.sh

② 添加以下内容

#!/bin/bash

SRC='/home/www/'
DEST='200@10.168.1.200::www/'
ACTIONS='attrib,create,modify,delete,moved_to,moved_from,delete_self'
LOG_FILE='/var/log/rsync_change.log'
SYNC_LOG='/var/log/rsync_sync.log'
ERROR_LOG='/var/log/rsync_error.log'

inotifywait -mrq \
--timefmt '%Y-%m-%d %H:%M:%S' \
--format '%T|%w|%f|%e' \
-e "$ACTIONS" \
"$SRC" |
while IFS='|' read -r DATETIME DIR FILE ACTION; do
DATE=${DATETIME% *}
TIME=${DATETIME#* }
FILEPATH="${DIR}${FILE}"

case "$ACTION" in
*MODIFY*) EVENT="被修改" ;;
*CREATE*) EVENT="被创建" ;;
*DELETE*) EVENT="被删除" ;;
*MOVED_FROM*) EVENT="被移出" ;;
*MOVED_TO*) EVENT="被移入" ;;
*ATTRIB*) EVENT="属性变更" ;;
*) EVENT="未知操作: $ACTION" ;;
esac

# 1) 逐事件记日志(不耗资源)
echo "${DATE} ${TIME} ${FILEPATH} ${EVENT}" >> "$LOG_FILE"

# 2) 防抖:1 秒内如果还有新事件,就继续读,不触发 rsync
# 直到 1 秒内没有新事件,才跳出内层循环,执行一次同步
while IFS='|' read -r -t 1 D2 W2 F2 E2; do
DATE=${D2% *}
TIME=${D2#* }
FILEPATH="${W2}${F2}"
case "$E2" in
*MODIFY*) EVENT="被修改" ;;
*CREATE*) EVENT="被创建" ;;
*DELETE*) EVENT="被删除" ;;
*MOVED_FROM*) EVENT="被移出" ;;
*MOVED_TO*) EVENT="被移入" ;;
*ATTRIB*) EVENT="属性变更" ;;
*) EVENT="未知操作: $E2" ;;
esac
echo "${DATE} ${TIME} ${FILEPATH} ${EVENT}" >> "$LOG_FILE"
done

# 3) 合并后只跑一次 rsync
if ! /usr/bin/rsync -az --delete \
--password-file=/etc/rsyncd.pwd.client \
"$SRC" "$DEST" >> "$SYNC_LOG" 2>&1; then
echo "$(date '+%F %T') rsync failed" >> "$ERROR_LOG"
fi
done


9.2 使用systemd服务开机自启脚本

① 创建一个 systemd 服务文件,例如 nano /etc/systemd/system/inotify-monitor.service,填写以下内容:

[Unit]
Description=Inotify File Monitor Service
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash /usr/local/bin/inotify_rsync.sh #脚本文件位置,比如/etc/systemd/system/inotify-monitor.service
Restart=on-failure
RestartSec=5
User=root #运行的用户,比如root

[Install]
WantedBy=multi-user.target

② 重新加载 systemd 配置并启动服务

systemctl daemon-reload

systemctl start inotify-monitor.service

③ 启用服务以便在系统启动时自动运行

systemctl enable inotify-monitor.service


10、 读写分离,定时校准

利用 inotifywait 捕获变化的文件列表,通过 rsync --files-from 只同步这些文件,避免全量扫描,大幅降低资源消耗(上面脚本已实现)

单独创建一个脚本,在每天业务低峰期(如凌晨)执行一次完整的 rsync --delete 同步。这次同步会全量扫描,找出并删除目标端多余的文件,确保两端最终状态一致。

① 创建全量同步脚本

nano /usr/local/bin/rsync_full_sync.sh

写入

#!/bin/bash
SRC='/home/www/'
DEST='200@10.168.1.200::www/'
SYNC_LOG='/var/log/rsync_full_sync.log'
ERROR_LOG='/var/log/rsync_error.log'

if ! /usr/bin/rsync -a --delete \
--password-file=/etc/rsyncd.pwd.client \
"$SRC" "$DEST" >> "$SYNC_LOG" 2>&1; then
echo "$(date '+%F %T') Full rsync failed" >> "$ERROR_LOG"
fi

② 给执行权限

chmod +x /usr/local/bin/rsync_full_sync.sh

③ 加 crontab(凌晨3点执行)

0 3 * * * /usr/local/bin/rsync_full_sync.sh >/dev/null 2>&1


11、日志防爆

每次触发脚本都会往日志里追加内容,尤其是全量同步每小时一次,rsync_full_sync.log 会越来越大。时间一长,可能把 /var/log 所在分区写满,导致系统或服务出问题,所以可加入日志防爆。

创建配置文件(把配置文件放到 /etc/logrotate.d/ 目录下就会自动执行)

nano /etc/logrotate.d/rsync-sync

写入

/var/log/rsync_full_sync.log
/var/log/rsync_sync.log
/var/log/rsync_change.log
/var/log/rsync_error.log
{
weekly
rotate 4
compress
missingok
notifempty
}

拆开分析:

前四行:要管理的日志文件列表。

weekly:每周轮转一次。也就是每周把当前日志改名备份,然后重新开始写新日志。

rotate 4:保留最近 4 份备份。第 5 份旧的会被自动删除。

compress:旧日志用 gzip 压缩,变成 .gz,省磁盘。

missingok:如果某个日志文件不存在,不报错,跳过。

notifempty:如果日志是空的,就不轮转,避免产生一堆空文件。


12、注意事项

① inotify存在资源耗尽的情况,每个 inotify 实例可以监视的最大数量是有限的,若报错“Please increase the amount of inotify watches allowed per user via `/proc/sy”,这可能是资源耗尽的问题。

在 Linux 内核中,inotify 实例可以监视的最大数量通常默认是 8192(可以通过 /proc/sys/fs/inotify/max_user_watches 查看)。如果应用程序创建了超过这个数量的监视器,就会耗尽资源。频繁的事件触发:如果监视的目录下有很多文件操作,例如频繁的文件创建和删除,某些操作(如文件移动)会生成多个事件(MOVED_FROM和MOVED_TO),也可能导致资源耗尽,因为内核需要维护这些事件的状态。

临时增加限制(仅对当前会话有效):

echo 524288 | sudo tee /proc/sys/fs/inotify/max_user_watches

永久增加限制(需要 root 权限):

sudo sysctl -w fs.inotify.max_user_watches=524288

也可以手动编辑 /etc/sysctl.conf文件,加入一下命令,保存并重启

fs.inotify.max_user_watches=8192000

② 网络文件系统可能不完全支持所有 inotify 事件


打赏

上一篇:Linux进程管理

下一篇:Linux端口详解

阅读排行

大家都在搜

博客维护不易,感谢你的肯定
扫码打赏,建议金额1-10元
  • 15601023311