只要服务器上有数据,就一定有"把数据同步到另一处"的需求:本机两个目录之间做镜像、把业务数据推到备份机、从远程服务器拉回日志归档、给多台机器分发配置文件。做这件事的工具,二十多年来答案始终是 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 守护进程模式要限来源、设强密码,非必要不对公网开放。
企业QQ咨询




