为什么 Rsync 是备份的基石
rsync 的核心价值是增量传输——只同步源和目标之间的差异块,而不是整文件复制。对比 scp/cp:
| 维度 | scp / cp | rsync |
|---|---|---|
| 传输单位 | 整个文件 | 差异块(rolling checksum) |
| 二次同步 | 全量重传 | 仅变化部分 |
| 断点续传 | 不支持 | 支持(--partial) |
| 删除同步 | 手动 | --delete 镜像 |
| 带宽限速 | 不支持 | --bwlimit |
| 远程传输 | scp 协议 | SSH / 守护进程 |
经典比喻:scp 是把整本书再抄一遍,rsync 是只把改动的几页重新抄。
工作原理(简化)
源文件 A ──┐
├─ 分块 + rolling checksum + MD5 → 比对目标文件 B 的校验
目标文件 B ─┘ │
▼
仅传输不匹配的块 + 重建目标文件
Rsync 把文件切成固定大小(默认 ~700 字节,可调 --block-size)的块,对每个块计算弱校验(rolling checksum,快速)和强校验(MD5,精确)。目标端已有相同块则跳过,只传输缺失/变化的块。
安装
# CentOS/RHEL
yum install -y rsync
# Ubuntu/Debian
apt install -y rsync
# 验证
rsync --version
基础用法
本地同步
# 同步目录(注意尾斜杠语义!)
rsync -av /data/source/ /data/backup/ # source/ 内容 → backup/
rsync -av /data/source /data/backup/ # 创建 backup/source/
# -a: 归档模式(递归+保留权限/时间戳/软链/属主)
# -v: 详细输出
# -z: 传输压缩(跨网络推荐)
# -h: 人类可读大小
尾斜杠是天坑:
rsync a/ b/把 a 的内容放进 b;rsync a b/把 a 目录放进 b(变成 b/a)。养成加尾斜杠的习惯。
远程同步(SSH 模式,最常用)
# 推送到远端
rsync -avz -e ssh /data/ root@backup.example.com:/data/backup/
# 从远端拉取
rsync -avz -e ssh root@backup.example.com:/var/www/ /local/www/
# 指定端口/密钥
rsync -avz -e "ssh -p 2222 -i /root/.ssh/backup_key" /data/ root@host:/backup/
排除规则
# 排除单个目录/文件
rsync -avz --exclude='node_modules' --exclude='*.log' /app/ remote:/app/
# 从文件读取排除列表
rsync -avz --exclude-from='exclude.txt' /data/ remote:/backup/
# exclude.txt 示例:
# *.tmp
# cache/
# .git/
# /secret.conf # 前导 / 表示从根开始匹配
镜像删除(危险但必要)
# 让目标完全镜像源(删除目标多余文件)
rsync -avz --delete /data/ remote:/backup/
# 先干跑(dry-run)确认影响
rsync -avzn --delete /data/ remote:/backup/
# 保护某些文件不被删除
rsync -avz --delete --exclude='important/' /data/ remote:/backup/
--delete会删除目标上源没有的文件——务必先-n干跑。生产环境配合--backup --backup-dir保留被删文件更稳妥。
生产级异地备份脚本
#!/bin/bash
# /usr/local/bin/rsync-backup.sh
# 每日异地增量备份 + 保留 7 天快照
set -euo pipefail
SRC="/data/app/"
DEST="root@backup.example.com:/data/backup/app/"
LOG="/var/log/rsync-backup.log"
EXCLUDE="/etc/rsync-exclude.txt"
SSH_OPTS="-p 2222 -i /root/.ssh/backup_key -o StrictHostKeyChecking=no"
DATE=$(date +%Y%m%d)
SNAP_DEST="root@backup.example.com:/data/snapshots/app/${DATE}/"
echo "[$(date)] 开始备份" >> "$LOG"
# 1. 主增量同步(带带宽限速,避免打满链路)
rsync -az --delete \
--bwlimit=10240 \ # 限速 10MB/s
--partial --partial-dir=.rsync-partial \
--exclude-from="$EXCLUDE" \
-e "ssh $SSH_OPTS" \
"$SRC" "$DEST" >> "$LOG" 2>&1
# 2. 生成当日硬链接快照(省空间,仅元数据)
ssh $SSH_OPTS root@backup.example.com \
"cp -al /data/backup/app/ /data/snapshots/app/${DATE}/" >> "$LOG" 2>&1
# 3. 清理 7 天前的快照
ssh $SSH_OPTS root@backup.example.com \
"find /data/snapshots/app/ -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;" >> "$LOG" 2>&1
echo "[$(date)] 备份完成" >> "$LOG"
硬链接快照(cp -al)原理:新快照只存变化的 inode 指针,未变文件硬链接到原文件——N 天快照几乎只占用 1 份空间,是廉价版本化备份的利器。
实时同步(inotify + rsync)
定时 rsync 有同步间隔,关键数据需要近实时。用 inotifywait 监控文件变化触发增量同步:
# 安装 inotify-tools
yum install -y inotify-tools
# 实时同步脚本
#!/bin/bash
SRC="/data/app/"
DEST="root@backup.example.com:/data/backup/app/"
SSH_OPTS="-p 2222 -i /root/.ssh/backup_key"
inotifywait -mrq -e modify,create,delete,move \
--format '%w%f' "$SRC" | while read file; do
rsync -az --delete -e "ssh $SSH_OPTS" "$SRC" "$DEST"
done
注意:每次变化都触发整目录 rsync 在文件频繁变动时效率低。改进:用
lsyncd(Lua 封装的 inotify+rsync,聚合多次变更后批量同步)或sersync。
lsyncd 配置(推荐)
-- /etc/lsyncd.conf.lua
settings {
logfile = "/var/log/lsyncd.log",
statusFile = "/var/log/lsyncd.status",
nodaemon = false,
maxProcesses = 4,
}
sync {
default.rsyncssh,
source = "/data/app/",
host = "backup.example.com",
targetdir = "/data/backup/app/",
rsync = {
archive = true,
compress = true,
_extra = {"--bwlimit=20480", "--delete"},
},
ssh = {
port = 2222,
identityFile = "/root/.ssh/backup_key",
},
delay = 5, -- 聚合 5 秒内的变更
}
守护进程模式(rsyncd)
SSH 模式每次要建立 SSH 会话,高频同步开销大。rsync 自带守护进程协议(端口 873),适合内网大规模同步:
# /etc/rsyncd.conf
uid = root
gid = root
use chroot = no
max connections = 10
pid file = /var/run/rsyncd.pid
log file = /var/log/rsyncd.log
[backup]
path = /data/backup
comment = App backup module
read only = no
list = no
auth users = rsync_user
secrets file = /etc/rsyncd.secrets
hosts allow = 10.0.0.0/24
# /etc/rsyncd.secrets
rsync_user:StrongPass!2026
chmod 600 /etc/rsyncd.secrets
# 启动守护进程
rsync --daemon
# 客户端同步(免 SSH)
rsync -avz --delete /data/app/ rsync_user@backup.example.com::backup/app/
安全提示:rsyncd 明文密码+无加密,务必配合
hosts allow限制来源,且仅在内网使用;公网场景优先 SSH 模式。
校验与恢复验证
# 1. 校验两端一致性(不传输,仅比对)
rsync -avnc /data/app/ remote:/backup/app/
# 2. 恢复:反向拉取
rsync -avz remote:/backup/app/ /data/app-restore/
# 3. 校验和全量比对(最严格,速度慢)
rsync -avc --checksum /data/app/ remote:/backup/app/
# 4. 备份完整性测试(随机抽取)
find /data/backup -type f | shuf | head -5 | while read f; do
test -s "$f" && echo "OK: $f" || echo "EMPTY: $f"
done
断点续传与大文件
# 大文件断点续传
rsync -avz --partial --partial-dir=.rsync-partial /bigfile.iso remote:/data/
# 临时文件目录需可写;同步中断后重跑会从上次断点继续
# 限制单文件传输对链路的影响
rsync -avz --bwlimit=5120 /data/ remote:/backup/ # 5MB/s
带宽与性能调优
| 参数 | 作用 | 建议 |
|---|---|---|
--bwlimit=KBPS |
限速 | 跨公网设为目标带宽的 70% |
--compress-level=N |
压缩级别 | 文本 6-9,已压缩文件(zip/视频)设 0 |
--block-size=SIZE |
块大小 | 大文件调大(如 16KB)减少校验开销 |
--whole-file |
禁用增量 | 内网高速链路可加速(跳过块比对) |
--inplace |
原地更新 | 减少临时空间占用,但中断可能损坏文件 |
避坑清单
| # | 坑 | 症状 | 解决 |
|---|---|---|---|
| 1 | 尾斜杠语义错 | 多嵌套一层目录 | 源和目标都加尾斜杠 / |
| 2 | --delete 误删 |
目标数据丢失 | 先 -n 干跑;配合 --backup-dir 留底 |
| 3 | 软链接被展开 | 同步出循环/多余数据 | 默认 -a 保留软链;要跟随加 -L |
| 4 | SSH 限速打满链路 | 业务卡顿 | 加 --bwlimit |
| 5 | 大文件无续传 | 网络抖动从头来 | --partial --partial-dir |
| 6 | 时间戳不保留 | 每次都全量比对 | 用 -a(含 -t)保留 mtime |
| 7 | 中文/空格文件名 | 同步失败 | 加 --protect-args 或用 -s |
| 8 | rsyncd 明文密码 | 凭证泄露 | 仅内网 + hosts allow 限制 |
| 9 | inotify 监听数超限 | 实时同步漏文件 | 调大 fs.inotify.max_user_watches |
| 10 | 硬链接快照占用爆盘 | 误以为不占空间 | 确认源未变;快照仅省未变部分空间 |
总结
Rsync 是 Linux 备份与同步的瑞士军刀,核心要点:
- 增量算法让它成为差异同步的事实标准——二次同步只传变化块
- SSH 模式安全通用(公网首选),守护进程模式高效(内网大规模)
--delete镜像 + 硬链接快照组合实现廉价版本化备份- inotify/lsyncd 把定时同步升级为近实时
--bwlimit+ 干跑-n是生产环境的安全底线
进阶:超大规模或跨云对象存储,可结合
rclone(支持 S3/OSS/COS 等对象存储作为 rsync 目标),把异地容灾直接落到云存储。
