Linux服务器如何使用rsync同步文件?增量同步与远程备份配置

只要服务器上有数据,就一定有"把数据同步到另一处"的需求:本机两个目录之间做镜像、把业务数据推到备份机、从远程服务器拉回日志归档、给多台机器分发配置文件。做这件事的工具,二十多年来答案始终是 rsync。它的核心优势是"增量同步"——只传输变化的部分,一个几 GB 的文件改动了几个字节,传输量可能只有几十 KB,这让它在带宽受限或数据量巨大的场景下不可替代。

但 rsync 同时也是"用得好和用不好差别极大"的工具。默认参数下它可能只同步文件名和大小、可能不删已删除的文件、可能因为一个字符的差异重传整个大文件;而一旦用了 --delete,一个路径写错就可能把目标端数据清空。所以真正需要掌握的,不只是"怎么敲命令",而是"每个关键参数到底改变了什么行为,以及哪些组合有风险"。

这篇文章会从 rsync 的工作原理讲起,覆盖本地同步、基于 SSH 的远程同步、rsync 守护进程模式三种用法,给出增量同步、镜像、带排除规则备份、限速传输、快照式备份等典型场景的完整命令,最后讲怎么用 cron 做定时备份,以及必须牢记的安全要点。命令同时给出 RHEL/CentOS/Rocky 和 Debian/Ubuntu 两套安装方式。

先建立核心认知:rsync 判断"文件是否需要传输"的依据,默认是文件的大小和修改时间(size + mtime),不是内容比对。 理解这一点,才能解释很多"为什么没同步"或"为什么又全传了一遍"的现象。

一、rsync 的工作方式与安装

rsync 的同步算法很简单也很聪明:源端和目标端各自算文件分块校验,只传输目标端缺失或变化的数据块。所以即使一个文件中间插入了一段内容,rsync 也能只传变化部分,而不是重传整个文件。这也是它比 scp、cp 更适合反复同步大批量数据的原因。

安装(多数发行版已自带):

# RHEL/CentOS/Rocky/AlmaLinux:
sudo yum install -y rsync
# 或
sudo dnf install -y rsync

# Debian/Ubuntu:
sudo apt update && sudo apt install -y rsync

# 查看版本
rsync --version

二、最基础的用法与几个必懂参数

rsync 的基本语法是 rsync [选项] 源 目标。本地同步示例:

# 把 /data/src 同步到 /data/dst(注意源路径末尾的斜杠含义不同)
rsync -av /data/src/ /data/dst/

# 干跑:只显示会做什么,不实际传输(强烈建议首次都先干跑)
rsync -av --dry-run /data/src/ /data/dst/

路径末尾的斜杠是 rsync 最大的坑之一,必须理解清楚:

  • rsync -av /data/src/ /data/dst/:同步 src 目录里的内容到 dst。
  • rsync -av /data/src /data/dst/:把 src 目录本身放进 dst,结果是 /data/dst/src/...。

差一个斜杠,结果完全不同。生产环境做镜像前,务必用 --dry-run 确认目录层级符合预期。

常用参数及含义:

参数 作用 说明
-a 归档模式 等于 -rlptgoD,保留权限、属主、时间等
-v 详细输出 显示同步过程
-z 传输压缩 适合网络传输,局域网可省
-P 进度 + 断点续传 等于 --partial --progress
--delete 删除目标端多余文件 做镜像必须,但极危险
--exclude 排除文件/目录 可多次使用
--exclude-from 从文件读排除规则 规则多时用
-n 干跑 同 --dry-run
--bwlimit 限速 单位 KB/s,避免占满带宽
-e ssh 指定远程 shell 可带 SSH 参数
--checksum 按校验和判断 更准但更慢
--link-dest 硬链接方式做快照 增量快照备份核心
--password-file 从文件读密码 配合守护进程模式
--numeric-ids 按数字 ID 保留属主 跨主机同步避免 UID 映射问题

三、基于 SSH 的远程同步(最常用)

大多数场景下,rsync 通过 SSH 隧道传输,既加密又无需额外开端口。方向分两种:

# 拉取(pull):从远程服务器拉到本地
rsync -avzP -e "ssh -p 22" user@203.0.113.10:/data/app/ /backup/app/

# 推送(push):从本地推到远程服务器
rsync -avzP -e "ssh -p 2222" /data/app/ user@203.0.113.10:/backup/app/

# 用 SSH 密钥免密(先做密钥,再同步)
ssh-keygen -t ed25519 -C "backup@host"     # 生成密钥
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@203.0.113.10   # 拷贝公钥
rsync -avzP -e "ssh -i ~/.ssh/id_ed25519 -p 22" /data/app/ user@203.0.113.10:/backup/app/

-p(小写,rsync 里表示保留权限)和 ssh -p(大写的端口)容易混,注意区分。

四、做镜像备份:--delete 的用法与风险

如果目标是"让备份端和源端完全一致",就需要 --delete,它会删除目标端那些源端已不存在的文件。这是做镜像的关键,也是最危险的参数。

# 镜像同步:源端删了什么,目标端也跟着删
rsync -av --delete /data/app/ /backup/app/

# 排除某些目录后再镜像(排除项不会被删除,也不会被传输)
rsync -av --delete \
      --exclude='cache/' \
      --exclude='tmp/' \
      --exclude='*.log' \
      /data/app/ /backup/app/

必须强调的风险:--delete 作用于目标端。如果源路径和目标路径写反,或者源目录因为某种原因变空(比如挂载失败),rsync 会把目标端数据全部删除。 有两个保险措施:

# 保险一:--delete-after(先传完再删,传输中断影响小)
rsync -av --delete-after /data/app/ /backup/app/

# 保险二:限制删除范围,只删目标端"源端曾有但现在没有"的文件
# 用 --max-delete 限制单次删除数量,避免误删规模失控
rsync -av --delete --max-delete=1000 /data/app/ /backup/app/

# 保险三:把要删除和传输的内容先列出来确认(干跑)
rsync -avn --delete /data/app/ /backup/app/

推荐用文件保存排除规则,避免命令行越来越长:

# /etc/rsync-exclude.txt
cat > /etc/rsync-exclude.txt <<'EOF'
cache/
tmp/
*.log
*.tmp
.git/
node_modules/
EOF

rsync -av --delete --exclude-from=/etc/rsync-exclude.txt /data/app/ /backup/app/

风险提示:--delete 会不可逆地删除目标端文件。执行前永远先 --dry-run(-n)确认将被删除的清单,确认源目录确实挂载正常、路径没有写反。回滚方式:如果备份端开启了快照或有多版本(下面讲的 --link-dest),可从快照恢复;否则只能从其它备份恢复。没有任何机制能让 --delete 误删的文件原地复原。

五、快照式增量备份:--link-dest

这是 rsync 最实用的进阶技巧:用硬链接做"看起来像全量、实际只占增量空间"的多版本备份。

# 备份根目录结构
# /backup/daily/2026-10-12/   今天的备份
# /backup/daily/2026-10-11/   昨天的备份(与今天共享未变文件)

BASE=/backup/daily
TODAY=$(date +%F)
LATEST=$(ls -1d $BASE/*/ 2>/dev/null | tail -1)

rsync -av --delete \
      --link-dest="${LATEST%/}" \
      /data/app/ "$BASE/$TODAY/"

--link-dest 的原理是:先拿上一次备份作为"参照",凡是没变化的文件,新备份里不复制内容,而是创建一个硬链接指向上一次的同一份数据。结果是每个日期目录看起来都是完整的全量,实际磁盘占用只有"变化部分 + 硬链接的元数据"。这样既能有多个可回滚的历史版本,又不会因为保留 30 天备份而占用 30 倍空间。

配套的清理策略(只保留最近 30 天):

# 删除 30 天前的备份目录(硬链接计数会自动减少,未共享的块被释放)
find /backup/daily -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;

六、限速、断点续传与大文件传输

备份常在业务时段跑,必须限制带宽,否则会拖垮线上的网络:

# 限速 20 MB/s(--bwlimit 单位是 KB/s,20480 KB/s ≈ 20 MB/s)
rsync -avz --bwlimit=20480 -e ssh /data/app/ user@203.0.113.10:/backup/app/

# 断点续传:--partial 保留未完成的临时文件,--progress 显示进度
rsync -avzP --partial-dir=.rsync-partial /data/bigfile user@203.0.113.10:/backup/

# 大文件强制校验(避免因 mtime 相同而漏同步)
rsync -avzP --checksum /data/bigfile user@203.0.113.10:/backup/

# 只传比目标端更新的文件(按修改时间)
rsync -avzP --update /data/app/ user@203.0.113.10:/backup/app/

经验值参考:在千兆内网(约 110 MB/s 实际吞吐)上,rsync 单流不开 -z 通常能跑到 80–100 MB/s;跨公网做压缩传输(-z)时,文本类数据压缩收益明显,已压缩过的文件(图片、视频、gz 包)加 -z 反而浪费 CPU,可以不加。

七、rsync 守护进程模式(rsyncd)

除 SSH 方式外,rsync 还能以服务方式运行,常用于内网批量备份或对外提供同步服务。配置文件是 /etc/rsyncd.conf:

# /etc/rsyncd.conf 示例
uid = rsync
gid = rsync
use chroot = yes
max connections = 20
pid file = /var/run/rsyncd.pid
log file = /var/log/rsyncd.log

[backup]
    path = /data/backup
    comment = backup area
    read only = no
    auth users = backupuser
    secrets file = /etc/rsyncd.secrets
    hosts allow = 203.0.113.0/24
    hosts deny = 0.0.0.0/0
# 创建认证文件(权限必须 600,格式:用户:密码)
echo "backupuser:StrongPassw0rd" | sudo tee /etc/rsyncd.secrets
sudo chmod 600 /etc/rsyncd.secrets
sudo chown root:root /etc/rsyncd.secrets

# 启动服务(systemd)
sudo systemctl enable --now rsyncd
sudo systemctl status rsyncd

# 客户端同步(双冒号表示走 rsync 协议,默认端口 873)
rsync -avz --password-file=/etc/rsync.pass backupuser@203.0.113.10::backup/ /data/local/

# 也可以指定端口
rsync -avz --port=873 backupuser@203.0.113.10::backup/ /data/local/

风险提示:rsync 守护进程默认端口 873,若要在公网暴露,务必限制 hosts allow、使用强密码、并配合防火墙。开放端口会扩大攻击面;若只是内部备份,优先用 SSH 方式,完全不必开 873 端口。回滚方式:如需关闭,systemctl stop rsyncd && systemctl disable rsyncd,并在防火墙删除放行规则。

八、用 cron 定时备份

把同步脚本化,交给 cron 定时执行:

# /etc/cron.d/rsync-backup
# 每天凌晨 2:30 执行备份
30 2 * * * root /usr/local/bin/backup-app.sh >/var/log/backup-app.log 2>&1
# /usr/local/bin/backup-app.sh 示例
#!/bin/bash
set -euo pipefail
BASE=/backup/daily
TODAY=$(date +%F)
LATEST=$(ls -1d "$BASE"/*/ 2>/dev/null | tail -1 || true)

rsync -az --delete --bwlimit=51200 \
      --link-dest="${LATEST%/}" \
      --exclude-from=/etc/rsync-exclude.txt \
      /data/app/ "$BASE/$TODAY/"

# 清理 30 天前的备份
find "$BASE" -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;

# 记录结果
echo "$(date '+%F %T') backup done, size: $(du -sh "$BASE/$TODAY" | cut -f1)"

脚本里加 set -euo pipefail 很重要:任何一步失败就退出,避免"rsync 失败了但清理还在跑"这种连锁问题。日志要保留,方便回溯哪天备份失败了。

常见问题

Q1:rsync 每次都在传同样的文件,为什么?
最常见的是文件的时间戳一直在变(比如应用在重写文件),或者跨文件系统后权限/属主差异导致 rsync 认为需要更新。可以加 --checksum 强制按内容判断,或排查是不是有进程在不停改文件 mtime。

Q2:--delete 会不会把源端的文件也删了?
不会,--delete 只作用于目标端。但正因为如此,源目录如果因为挂载故障变空,rsync 会认为"源端没有文件了",从而删光目标端。所以备份脚本执行前最好加一句 mountpoint -q /data && ... 做保护。

Q3:-a 和 -r 有什么区别?
-r 只递归复制,不保留权限、属主、时间;-a 是归档模式,保留这些属性。备份场景一律用 -a。

Q4:跨主机同步后属主全乱套了?
因为两端用户 UID 不一致。加 --numeric-ids 按数字 ID 同步,或提前在两台机器上统一 UID。

Q5:rsync 能同步正在写入的文件吗?
可以传,但传过去的可能是"某个时间点的快照"或部分内容。对数据库这类持续写的文件,应先做逻辑备份(如 mysqldump)或文件系统快照,再同步备份文件。

总结

  • rsync 的核心是增量传输,默认按"大小 + 修改时间"判断是否需要同步,可用 --checksum 改为按内容判断。
  • 重视路径末尾的斜杠:带斜杠同步的是目录内容,不带斜杠会把目录本身放进去。
  • --delete 是做镜像的必要参数,但也是最危险的,永远先 --dry-run 并确认源挂载正常。
  • --link-dest + 按日期命名目录,能实现"多版本全量外观、增量实际占用"的高效备份。
  • 备份脚本加限速(--bwlimit)、排除规则(--exclude-from)、失败即退出(set -euo pipefail),并保留日志。
  • 内部备份优先用 SSH 方式;rsync 守护进程模式要限来源、设强密码,非必要不对公网开放。