在CentOS服务器上做实时目录备份,最实用的方案就是rsync配合inotify-tools。rsync负责增量同步,只传输变化的文件,节省带宽和时间;inotify负责监控目录变动,一旦有文件新增、修改或删除,立刻触发rsync同步。这套组合比传统的crontab定时备份强太多,因为它是事件驱动的,延迟通常在秒级,真正做到了"实时"。下面我从安装、配置、脚本编写到生产环境优化,一步步给你讲透。

一、为什么选rsync+inotify而不是其他方案

很多运维新手会问,备份方案那么多,为什么偏偏推荐这套?原因很简单。第一,rsync是Linux下最成熟的文件同步工具,支持增量传输、断点续传、保留权限和时间戳,而且不需要在目标端安装服务端程序。第二,inotify是Linux内核自带的文件系统事件通知机制,不需要轮询,性能开销极低。第三,两者结合可以实现"文件一变就同步",而不是等五分钟、十分钟才跑一次定时任务。对于数据库文件、用户上传目录、配置文件这些高频变动的场景,这套方案几乎是标配。

二、环境准备和软件安装

首先确保你的CentOS版本是7或8,内核版本3.10以上就自带inotify支持。先安装inotify-tools,这个包提供了inotifywait命令行工具,方便我们在脚本里调用。

yum install -y inotify-tools rsync

rsync一般CentOS自带,如果没有就一起装上。安装完验证一下:

rsync --version
inotifywait --version

两个命令都能输出版本号,说明环境没问题。接下来要确认源目录和目标目录都存在,目标目录可以是本机另一个路径,也可以是远程服务器的路径。如果是远程同步,需要配置SSH免密登录,否则每次同步都要输密码,根本没法自动化。

三、配置SSH免密登录(远程同步必备)

假设源服务器是192.168.1.100,目标备份服务器是192.168.1.200。在源服务器上生成密钥:

ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa

然后把公钥拷贝到目标服务器:

ssh-copy-id root@192.168.1.200

拷贝完成后测试一下:

ssh root@192.168.1.200 "echo ok"

如果直接返回ok不需要输密码,免密登录就配好了。这一步非常关键,不配好后面脚本跑不起来。

四、编写实时同步脚本

下面是核心脚本,我给你写一个完整可用的版本,包含注释,你可以直接拿去改路径用:

#!/bin/bash
# rsync+inotify实时同步脚本
# 监控本地目录 /data/www 同步到远程 /backup/www

SRC_DIR="/data/www"
DEST_HOST="192.168.1.200"
DEST_DIR="/backup/www"
RSYNC_OPTS="-az --delete --progress"
LOG_FILE="/var/log/rsync_inotify.log"

# 记录日志函数
log_msg() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE
}

log_msg "开始监控目录: $SRC_DIR"

# 使用inotifywait监控目录事件
inotifywait -mrq --timefmt '%Y-%m-%d %H:%M:%S' --format '%T %w%f %e' \
    -e modify,create,delete,move "$SRC_DIR" | while read DATE TIME FILE EVENT
do
    # 忽略临时文件和隐藏文件
    if [[ "$FILE" == .* ]]; then
        continue
    fi

    log_msg "检测到事件: $EVENT 文件: $FILE"

    # 延迟2秒执行同步,避免频繁触发(合并短时间内的多次变动)
    sleep 2

    # 执行rsync同步
    rsync $RSYNC_OPTS "$SRC_DIR/" "root@${DEST_HOST}:${DEST_DIR}/" >> $LOG_FILE 2>&1

    if [ $? -eq 0 ]; then
        log_msg "同步成功: $FILE"
    else
        log_msg "同步失败: $FILE"
    fi
done

这个脚本的逻辑是:inotifywait持续监控源目录,一旦检测到modify(修改)、create(新建)、delete(删除)、move(移动)事件,就等待2秒后触发rsync同步。为什么要等2秒?因为有时候一个大文件写入会触发多次modify事件,合并一下可以减少不必要的同步次数,降低系统负载。

五、脚本参数详解和优化建议

上面脚本里的rsync参数值得单独说说。-a是归档模式,保留权限、所有者、时间戳、符号链接等所有属性。-z是压缩传输,适合网络同步,本地同步可以去掉。-delete参数意味着目标端删除的文件源端也删,保持两端完全一致。如果你只想单向增量备份、不想删除目标端文件,就把--delete去掉。

inotifywait的参数也有讲究。-m表示持续监控不退出,-r表示递归监控子目录,-q表示安静模式只输出事件。--timefmt和--format用来自定义输出格式,方便日志记录。如果你只监控单层目录不需要递归,把-r去掉就行,性能会更好。

六、设置为系统服务实现开机自启

脚本写好了不能手动跑,得做成systemd服务,服务器重启后自动拉起。创建服务文件:

vim /etc/systemd/system/rsync-inotify.service

写入以下内容:

[Unit]
Description=Rsync Inotify Real-time Sync Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/rsync_inotify.sh
Restart=always
RestartSec=5
User=root

[Install]
WantedBy=multi-user.target

然后把脚本放到对应位置并赋予执行权限:

cp rsync_inotify.sh /usr/local/bin/rsync_inotify.sh
chmod +x /usr/local/bin/rsync_inotify.sh

启动并设置开机自启:

systemctl daemon-reload
systemctl start rsync-inotify
systemctl enable rsync-inotify

用systemctl status rsync-inotify查看运行状态,active (running)就说明正常了。

七、生产环境的注意事项和坑

第一,inotify有监控上限。默认情况下,Linux对每个用户的inotify实例数和监控文件数有限制,可以通过/proc/sys/fs/inotify/max_user_watches查看。如果你监控的目录文件特别多,比如几十万个小文件,需要调大这个值:

echo 524288 > /proc/sys/fs/inotify/max_user_watches

永久生效写到/etc/sysctl.conf里:

fs.inotify.max_user_watches = 524288

第二,rsync同步大文件时会占用带宽和IO,如果源服务器业务繁忙,建议加一个限速参数--bwlimit=50000,限制在50MB/s以内,避免影响正常业务。

第三,日志文件会越来越大,建议配合logrotate做日志轮转,否则几个月就把磁盘写满了。

第四,如果目标服务器挂了或者网络断了,inotifywait不会报错但rsync会失败。建议在脚本里加一个重试机制,失败后等30秒再试一次,连续失败3次就发告警通知。这个可以用邮件或者企业微信、钉钉的webhook来实现。

八、替代方案对比:为什么不用lsyncd

有人可能听说过lsyncd,它也是基于inotify+rsync的实时同步工具,而且是用Lua写的,配置更简洁。确实,如果你只是做简单的单向同步,lsyncd开箱即用。但它的缺点是灵活性不够,比如你想在同步前后执行自定义脚本、做文件过滤、加复杂的判断逻辑,lsyncd就不太方便了。自己写脚本虽然前期麻烦一点,但后期维护和扩展都更自由。对于企业级运维来说,我更推荐自己掌控脚本逻辑。

九、总结

rsync+inotify这套方案,本质上是用最小的成本实现了准实时的文件同步。它不需要额外的商业软件,不需要复杂的架构,一台CentOS服务器加上几十行脚本就能搞定。关键是要把SSH免密配好、脚本参数调对、服务做成systemd自启,再加上监控告警和日志管理,就是一套完整的生产级备份方案。不管是Web站点文件备份、用户数据同步还是配置文件容灾,这套组合都能胜任。运维这件事,工具选对了,效率翻倍。