Linux运维10 min read次阅读

Rsync 增量同步与异地容灾实战

为什么 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 备份与同步的瑞士军刀,核心要点:

  1. 增量算法让它成为差异同步的事实标准——二次同步只传变化块
  2. SSH 模式安全通用(公网首选),守护进程模式高效(内网大规模)
  3. --delete 镜像 + 硬链接快照组合实现廉价版本化备份
  4. inotify/lsyncd 把定时同步升级为近实时
  5. --bwlimit + 干跑 -n 是生产环境的安全底线

进阶:超大规模或跨云对象存储,可结合 rclone(支持 S3/OSS/COS 等对象存储作为 rsync 目标),把异地容灾直接落到云存储。

分享:

相关文章

评论区