基于 rsync 和硬链接的 ext4 系统回滚:实用实现方案
标准的 Linux ext4 安装缺乏内置快照支持,这使得快速回滚到先前状态变得困难。像 borg 或 restic 这样的备份工具侧重于长期数据存储,而非本地回滚。从完整备份恢复需要数小时并涉及处理大量数据,这对于修复本地配置错误或更新后问题来说效率低下。
该解决方案最小化依赖:无需更改文件系统、使用 LVM 或采用 Btrfs/ZFS 等专用文件系统。该方法依赖于支持硬链接去重的 rsync。
工作原理:rsync + 硬链接
rsync 通过仅复制更改来同步目录。--link-dest 选项允许引用先前的快照:未更改的文件通过硬链接重用,从而最小化存储使用。硬链接是同一 inode 的额外名称,确保未更改数据零开销。
创建快照的基本命令:
rsync -aHAX --numeric-ids --delete --link-dest="$PREV" "$SRC" "$DEST_TMP/"
-a:归档模式(递归,保留权限、时间戳)。-H:保留硬链接。-A:保留 ACL。-X:保留扩展属性。--numeric-ids:使用数字 UID/GID。--delete:删除目标目录中的额外文件。
这将当前状态同步到快照,仅复制增量部分。
快照存储结构
快照存储在 .infra_snapshots/ 中,作为带时间戳的常规目录:
.infra_snapshots/
├── system/
│ ├── 2026-03-01_00-30-00/
│ ├── 2026-03-02_00-30-00/
│ └── LATEST -> 2026-03-02_00-30-00/
├── docker/
│ ├── 2026-03-01_23-30-00/
│ └── LATEST -> 2026-03-01_23-30-00/
LATEST 符号链接指向最新快照以用于自动化。分离 system 和 docker 将系统文件与容器数据隔离:排除 Docker 卷以避免可变数据问题。
创建过程:
- 创建临时目录
.tmp-YYYY-MM-DD_HH-MM-SS。 - 运行 rsync 到其中。
- 原子重命名:
mv -T "$TMP_DEST" "$FINAL_DEST"。 - 更新
LATEST:ln -sfn "$FINAL_DEST" "$LATEST_LINK"。
这确保了原子性:快照要么完整,要么不存在。
恢复状态
回滚涉及反向同步,并使用试运行预览:
rsync -aHAX --numeric-ids --delete --dry-run "$SNAP/" "/"
验证后,移除 --dry-run 以应用。rsync 将根系统恢复到快照状态,删除新文件并通过硬链接恢复旧文件。
对于 Docker:类似操作,但仅在容器目录上,排除卷。
方法的局限性
- 缺乏系统原子性:rsync 顺序读取文件;系统可能在创建期间更改。快照是文件一致的,但非瞬时。
- 可变数据:日志、数据库和临时文件可能处于中间状态。使用
--exclude从 rsync 中排除它们。 - 磁盘空间:新文件版本占用空间;定期清理旧快照。
- 不适用于高负载生产环境:适用于快照创建期间活动较少的服务器/桌面。
| 场景 | 创建时间(约) | 磁盘使用 |
|----------|---------------------------|---------------|
| 每日系统 | 2-5 分钟 | 100-500 MB |
| 更新后 Docker | 1-3 分钟 | 50-200 MB |
自动化
集成到 cron 以进行每日快照:
- 00:30:系统。
- 23:30:docker。
脚本应记录 rsync 输出,检查退出代码,并在错误时通知。
关键点:
- 使用
--link-dest的 rsync 在 ext4 上模拟快照,无需更改文件系统。 - 硬链接提供去重:未更改的文件不重复。
- 通过临时目录实现原子性,防止部分快照。
- 分离系统/docker 提高回滚准确性。
- 恢复前试运行对安全至关重要。
该方法透明,仅使用标准 Linux 工具,并可扩展到任何 ext4 系统。
— Editorial Team
暂无评论。