前言
数据要在两台机器间保持同步——备份、分发、迁移——十几年过去了,答案依然是 rsync:增量传输、断点续传、保持属性、走 SSH。配合 inotify 触发,还能做到准实时同步。
一、rsync 核心概念
增量算法:两端比对块校验和,只传差异部分——同步 100GB 的目录,改动 10MB 就只传 10MB。
源 ──►(差异计算)──► 目标
滚动校验和比对, 只传变化的块
三种工作模式:
# 1. 本地同步
rsync -av /data/src/ /data/backup/
# 2. 远程(走 SSH, 最常用)
rsync -av /data/src/ user@backup:/data/backup/
# 3. 守护进程模式(rsyncd, 大量数据/免交互)
rsync -av /data/src/ rsync://backupHost/mod-backup/
二、必懂参数与斜杠陷阱
rsync -avz --delete /data/src/ backup:/data/backup/
| 参数 | 含义 |
|---|---|
-a |
归档模式(递归+保持权限/时间/属主/软链) |
-v |
显示过程 |
-z |
传输时压缩(文本目录很值; 已压缩文件别开) |
--delete |
删除目标端多余文件(镜像同步; 生产慎用!) |
-P |
显示进度+断点续传(= –partial –progress) |
--exclude |
排除(可多次) |
-n / --dry-run |
演练模式(只说要做啥, 不真做) |
--bwlimit=10240 |
限速 10MB/s(避开业务高峰) |
斜杠决定语义(新手第一大坑):
rsync -av /data/src /backup/ # → /backup/src/... 同步"src目录本身"
rsync -av /data/src/ /backup/ # → /backup/... 同步"src里的内容"
排错利器 dry-run:
# 永远先演练, 尤其带 --delete 时!
rsync -avn --delete /data/src/ backup:/data/backup/ | head
三、实战:每日增量备份
#!/usr/bin/env bash
# /opt/scripts/backup-data.sh
set -euo pipefail
SRC="/data/app/"
DEST="backup@10.0.2.50:/backup/app-$(hostname)/"
LOG="/var/log/rsync-backup.log"
exec >>"$LOG" 2>&1
echo "=== $(date '+%F %T') 备份开始 ==="
rsync -az --delete \
--exclude="*.tmp" \
--exclude="cache/" \
--bwlimit=51200 \
-e "ssh -p 22 -i /home/backup/.ssh/id_ed25519" \
"$SRC" "$DEST"
echo "=== 备份完成, 同步 $(du -sh $SRC | cut -f1) ==="
配合 cron(每日 2 点):
# /etc/cron.d/data-backup
0 2 * * * backup /opt/scripts/backup-data.sh
镜像型备份的缺陷:源被误删/中勒索,--delete 会把备份也同步删掉!必须配合快照或版本化:
# 版本化: 每天一个硬链接快照目录(rsync --link-dest 神器)
TODAY=/backup/app/$(date +%F)
YESTERDAY=/backup/app/$(date -d yesterday +%F)
rsync -a --delete --link-dest="$YESTERDAY" /data/app/ "$TODAY/"
# 未变化的文件 = 硬链接(0额外空间), 变化的文件 = 新副本
# 效果: 每天完整视图 + 增量磁盘占用
四、inotify:实时触发同步
rsync 本身是"轮询全量比对",inotify 让文件一变化就触发:
dnf install -y inotify-tools
# 监控目录事件
inotifywait -mrq /data/web \
-e create,modify,delete,move,close_write \
--format '%w%f %e' | while read -r file event; do
echo "[$event] $file"
done
组合成实时同步服务:
#!/usr/bin/env bash
# /opt/scripts/realtime-sync.sh(用 systemd 常驻)
set -euo pipefail
SRC=/data/web/
DEST=web@10.0.2.60:/data/web/
LOCK=/var/run/realtime-sync.lock
# 防重入
exec 9>"$LOCK"; flock -n 9 || exit 0
# 先做一次全量基线
rsync -a --delete "$SRC" "$DEST"
# 监听变化, 攒 2 秒批量同步(避免高频触发)
inotifywait -mrq "$SRC" -e create,modify,delete,move,close_write --format '%w%f' |
while read -r _; do
sleep 2
rsync -a --delete "$SRC" "$DEST"
done
# /etc/systemd/system/realtime-sync.service
[Unit]
Description=Realtime sync /data/web
After=network-online.target
[Service]
ExecStart=/opt/scripts/realtime-sync.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
inotify 的坑:
| 问题 | 处理 |
|---|---|
| 大目录报队列溢出 | sysctl fs.inotify.max_user_watches=524288 |
| 极高频写入刷爆 rsync | 批量节流(如上 sleep);或改 lsyncd |
| 只适合单向 | 双向同步不要双机互 rsync(会脑裂),要双向用 syncthing/unison |
lsyncd:lua 封装的 inotify+rsync,配置化更优雅:
-- /etc/lsyncd.conf.lua
settings { logfile = "/var/log/lsyncd.log", statusFile = "/var/log/lsyncd.status" }
sync {
default.rsync,
source = "/data/web",
target = "web@10.0.2.60:/data/web",
delay = 3,
rsync = { archive = true, delete = true }
}
五、rsync 守护进程模式(免 SSH 大带宽场景)
# /etc/rsyncd.conf(服务端, 备份机)
uid = backup
gid = backup
use chroot = yes
max connections = 10
[mod-backup]
path = /backup/app
comment = app backup
read only = false
auth users = syncer
secrets file = /etc/rsyncd.secrets # 格式: syncer:密码, 权限600
systemctl enable --now rsyncd
# 客户端
rsync -az --password-file=/etc/rsync.pass /data/app/ \
rsync://syncer@10.0.2.50/mod-backup/
六、同步方案选型表
| 需求 | 方案 |
|---|---|
| 每日备份 | cron + rsync -a + –link-dest 版本化 |
| 准实时单向 | inotify+rsync / lsyncd |
| 双向同步 | syncthing / unison |
| 海量小文件 | rsync 排除临时 + --whole-file 局域网加速 |
| 跨机房/公网 | rsync over SSH 或对象存储同步工具 |
| 数据库 | 别直接 rsync 活库!逻辑备份(xtrabackup/mysqldump)后同步 |
七、排障速查
# 权限错误
rsync: chown ... failed: Operation not permitted
→ 目标端无 root; 去掉属主保留(-a 里去掉 -o -g: 用 -rlptD)
# 速度慢
→ 看是否走了压缩大文件; 局域网加 --whole-file; 公网加 -z
→ iostat 看磁盘是否瓶颈; --bwlimit 反向确认没被限速
# @ERROR: auth failed
→ secrets 文件权限600; 用户名密码对齐服务端
# inotify 无输出
→ 内核 watches 上限; 监控路径是否挂载点(跨文件系统要分层监控)
小结
| 场景 | 命令要点 |
|---|---|
| 日常同步 | rsync -avz --exclude 注意结尾斜杠 |
| 镜像同步 | --delete 必先 dry-run |
| 备份保护 | --link-dest 版本化快照 |
| 实时单向 | inotifywait + flock + 批量节流 |
| 常驻服务 | systemd Restart=always |
本文是「Linux 运维」系列第 15 篇。