rsync 增量备份的三个必踩参数:--delete、-avz 与断点续传

举报
yd_242458115 发表于 2026/11/02 10:12:46 2026/11/02
【摘要】 一条带了 --delete 的 rsync,在源端挂载失败、目录为空时,把目标端 8 万多个文件全部删掉,退出码还是 0。这篇文章讲清三件事:-a 与 -avz 的实际差别、--delete 该配的三个保险、断点续传该用哪个参数。

一次带了 --delete 的 rsync,在源端挂载失败、目录变成空的情况下,把目标端 8 万多个文件全部删掉。整个过程没有任何报错,退出码还是 0。原因很直接:rsync 只认一条规则——源端没有的文件,目标端也要删掉。它分不清"这些文件确实不要了"和"源端根本没挂上、目录是空的"。

这不是 rsync 的缺陷,这个参数本来就该这么工作。真正要做的是在使用前把边界框住。下面按实际排障顺序,把三个最危险的参数讲清楚。

一、-a 到底展开成什么

-a 是 -rlptgoD 的缩写:递归、保留符号链接、权限、时间戳、属主、属组、设备文件。它不包含硬链接(-H)、ACL(-A)、扩展属性(-X)、校验(-c)、压缩(-z)、详细输出(-v)。

换句话说,-a 覆盖的是"普通文件的完整副本"。遇到 git 仓库、容器镜像层、带安全标签的目录,光靠 -a 就会漏东西。按需补:

  • -a 等于 -rlptgoD,普通文件备份的默认项;
  • -avz 是在 -a 上再压一遍,只有链路带宽紧张时才划算;
  • -aHAX 补硬链接、ACL、扩展属性,备份 git 仓库、容器层、带安全标签的目录必须加。

二、-z 在内网是负收益

同一个 400GB 的照片目录做过两组对照:加 -z 跑完 6 小时 40 分,去掉 -z 同样内容只要 4 小时 10 分。原因很朴素——JPEG 和视频本身已经压过,gzip 再压几乎不缩小,纯烧 CPU。rsync 两端各起一个压缩进程,CPU 先打满,网卡根本跑不满,整体反而更慢。

要不要 -z 只看两件事:链路带宽和文件类型。千兆起步、以图片视频为主,一律不用;跨公网、以文本日志为主,才加。拿一份 1GB 样本自己量,别凭感觉:

time rsync -a  /srv/data/sample/ /mnt/backup/s1/
time rsync -avz /srv/data/sample/ /mnt/backup/s2/

三、--delete 必须配三个保险

三个保险的作用都是"在不可逆动作前多一道确认",任何一个都比事后恢复便宜。

第一个是 --dry-run。输出里以 *deleting 开头的行,就是它准备删掉的东西,先看清单再决定:

rsync -aHAX --delete --dry-run --itemize-changes \
  --exclude-from=/etc/backup/exclude.txt \
  /srv/data/ /mnt/backup/data/ | grep '^\*deleting' | head -n 20
rsync -aHAX --delete --dry-run /srv/data/ /mnt/backup/data/ | grep -c '^\*deleting'

第二个是 --max-delete=200。超过阈值 rsync 会以退出码 25 中断,不会删到一半接着删。正常日变更的删除量不到 30 个,一旦爆量就说明源端出了问题,这时候停下来比删完更值钱。

第三个也是最有效的一个:在脚本里挡一道源目录健康检查。rsync 自己分不清"空目录"和"没挂上的目录",但 shell 分得清:

set -euo pipefail
src=/srv/data
cnt=$(find "$src" -maxdepth 1 -type f | wc -l)
[ "$cnt" -ge 100 ] || { echo "源目录只有 $cnt 个文件,疑似未挂载,中止" >&2; exit 3; }
mountpoint -q "$src" || { echo "$src 不是挂载点" >&2; exit 3; }

四、尾部斜杠差一层目录

/srv/data/ 表示"data 里的内容",/srv/data 表示"data 这个目录本身"。少一个斜杠,备份结果就从 backup/data/… 变成 backup/data/data/…。这个差别做镜像时看不出来,等到恢复那天才发现多出一层目录,所有指向绝对路径的配置全部失效。

记法很简单:源永远结尾带斜杠,目标永远不带。写死成习惯,就不用每次重新想一遍。

五、断点续传不是它的卖点

rsync 默认把新文件写成临时文件,传完再改名,所以中断时目标端不会留半个坏文件——代价是重跑仍要从头传这个大文件。要续传得显式加参数:

rsync -aHAX --partial --append-verify --info=progress2 \
  /srv/data/big.iso /mnt/backup/data/

--append-verify 只对"目标端已有同前缀"的文件有效,源端文件被改过就会校验失败重传,所以别对会变的文件用它。跨天跑的大传输更适合 --partial-dir=.rsync-partial,残片放在目标端的隐藏目录里,下次自动接上。

六、用 --link-dest 做省空间的日备份

每天一份全量听着奢侈,但硬链接一挂,只有变化的文件才占新空间:

set -euo pipefail
day=$(date +%F)
src=/srv/data/
dst=/mnt/backup/data
mkdir -p "$dst/$day"
rc=0
rsync -aHAX --numeric-ids --delete --max-delete=200 \
  --link-dest="$dst/latest" "$src" "$dst/$day/" || rc=$?
if [ "$rc" -ne 0 ] && [ "$rc" -ne 24 ]; then echo "rsync rc=$rc" >&2; exit 1; fi
rm -f "$dst/latest" && ln -s "$day" "$dst/latest"

1.2TB 的目录,首份全量占 1.2TB,之后每天只多 8 到 40GB。--numeric-ids 一定要加,否则目标端会按用户名重新映射,uid 全变,ls -l 一看全是陌生所有者,恢复时还得逐个改回去。

退出码别偷懒:24 表示"传输中源端文件消失了",属于正常噪声;23 是部分文件传输失败;0 才是全好。只判 0 会让正常备份天天报警,只判非 0 会让真故障被吞掉。

七、一条可直接落地的命令

rsync -aHAX --numeric-ids --delete --max-delete=200 \
  --exclude='.cache/' --exclude='*.tmp' \
  --bwlimit=80M --info=stats2 \
  /srv/data/ /mnt/backup/data/

落地前跑三遍:一次 --dry-run 看清单,一次 --itemize-changes 看差异,一次真跑看耗时和退出码。三次都对,才放进定时任务。

一句话结论:--delete 是唯一能一次性毁掉备份的参数,它前面那道"源目录文件数 + 是否挂载点"的检查,比后面所有参数都值钱;-z 在内网只会拖慢,--numeric-ids 和 --max-delete 才是必须项。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。