用 rsync 做增量备份:比全量拷贝省 90% 时间
用 rsync 做增量备份:比全量拷贝省 90% 时间
备份这件事,很多人第一版实现都是 cp -r 或者 tar 打包整个目录。数据量小的时候没问题,一旦目录到了几十 GB、几百万个小文件,每次全量拷贝既慢又占空间,磁盘 I/O 还会把线上服务拖慢。
rsync 解决的就是这个问题:它只传输变化的部分。这篇文章记录一套可以直接用的增量备份方案。
rsync 为什么快
rsync 的默认算法是「快速检查」:先比较文件大小和修改时间(mtime),两者都一致就跳过,不再读文件内容。这意味着对绝大多数场景,它根本不会去传输没变的文件。
如果需要更严格的校验,可以加 -c 参数让它计算校验和。代价是要把两边文件都读一遍,速度会慢很多,适合对数据完整性要求极高的场景。
另一个关键点是 rsync 的传输协议:即使文件变了,它也只传差异块,而不是整个文件。对大文件(数据库文件、日志归档)效果非常明显。
一条能用的命令
rsync -aHAX --delete --numeric-ids \
--exclude='*.tmp' --exclude='cache/' \
/data/ backup@192.0.2.10:/backup/data/
参数逐个说明:
-a归档模式,等价于-rlptgoD,保留权限、时间、软硬链接、属主属组-H保留硬链接。备份大量重复文件(比如 Docker 镜像层)时必须加,否则硬链接会被展开成独立文件,体积暴涨-A保留 ACL,-X保留扩展属性。SELinux 环境或者用了 setfacl 的目录必须加--delete让目标端删除源端已删除的文件,保持严格镜像--numeric-ids按数字 UID/GID 同步,不查用户名。跨机器、容器环境里用户名对不上时,不加会把属主改错
--delete 是有风险的参数:如果源目录挂载失败变成空目录,rsync 会把备份也清空。稳妥做法是加 --delete-after(先传完再删)配合 --dry-run 先跑一遍看清单。
增量备份到不同日期目录
严格镜像只能保留最新一份,误删文件会被同步过去。要保留历史版本,可以用硬链接快照:
#!/bin/bash
set -euo pipefail
SRC=/data/
DEST=/backup/snapshots
TODAY=$(date +%Y-%m-%d)
LATEST=$(ls -1d "$DEST"/2* 2>/dev/null | tail -1)
mkdir -p "$DEST/$TODAY"
if [ -n "$LATEST" ]; then
rsync -aHAX --numeric-ids --delete \
--link-dest="$LATEST" "$SRC" "$DEST/$TODAY/"
else
rsync -aHAX --numeric-ids "$SRC" "$DEST/$TODAY/"
fi
--link-dest 是关键:rsync 会把没变的文件硬链接到上一份快照,只有变化的文件才占新空间。这样每天的「全量快照」实际只多出增量部分的磁盘占用,但恢复时每个目录都是完整的、可直接拷回去的树。
实测一个 40 GB 的目录,首次备份 12 分钟,之后每天增量约 1 分钟,单日新增占用 200 MB 到 1 GB 不等。
常见坑
mtime 不可信会导致漏备份。 有些程序写完文件不改 mtime(或者被 touch 重置),rsync 会误判为未变化。这类目录要么加 -c,要么在备份前 touch 一下。
跨文件系统同步丢硬链接。 硬链接不能跨文件系统,如果目标盘和源盘不在同一个 fs 上,-H 会退化成复制。硬链接快照方案要求 $DEST 内部是同一个文件系统。
排除规则写错会漏文件。 --exclude='cache' 匹配任意层级的 cache,而 --exclude='/cache' 只匹配根目录下的。排除规则多的时候建议写成文件,用 --exclude-from=rules.txt 管理。
中断后重跑不需要特殊处理。 rsync 支持断点续传,--partial 会保留未完成的临时文件,重跑时接着传。不加这个参数的话,中断的大文件下次会从头开始。
什么时候不该用 rsync
rsync 适合「文件级」备份。数据库这类有自己事务日志的服务,直接同步数据文件可能拿到不一致的状态,正确做法是先做逻辑导出(mysqldump、pg_dump)或者用文件系统快照(LVM、ZFS、btrfs snapshot)再同步快照。
另外 rsync 是单线程的,超大目录(千万级 inode)扫描阶段会成为瓶颈。这种规模可以考虑 btrfs send/receive 或者分布式方案。
小结
rsync 的价值不在「能拷文件」,而在「只拷变化的、能保留元数据、能构造硬链接快照」。一套 --link-dest 的每日快照脚本大约 20 行,就能覆盖大部分中小规模备份需求,恢复时也不需要任何特殊工具,直接把目录拷回去即可。
- 点赞
- 收藏
- 关注作者
评论(0)