起因
我们的备份服务器收 rsync from 多台业务机器。问题:
- rsync 跑到一半,业务机继续写新文件 → 备份目录里出现"part-A from 12:00,
part-B from 12:15" 时间错乱的版本 - 备份过程中如果客户端机器挂了 → 备份目录是半新半旧
- 想"备份这一刻的整盘快照" 而不是"几小时内分散的快照"
如果备份目标是 ZFS 文件系统,可以利用 ZFS snapshot 做"事务性"备份:
- rsync 完整跑完
- 跑完后立即 zfs snapshot
- 之后业务继续 rsync 上新数据
- snapshot 是这一刻完整一致的副本
完整流程
setup
备份服务器 NAS 上:
# 创建一个 ZFS dataset 收备份
sudo zfs create backuptank/clients/server-foo
sudo zfs set compression=zstd backuptank/clients/server-foo
sudo zfs set atime=off backuptank/clients/server-foo
# 给 rsync 用户写权限
sudo zfs allow rsync-user create,destroy,snapshot,mount backuptank/clients/server-foo
业务机推送 + snapshot 脚本
#!/usr/bin/env bash
# /usr/local/sbin/snap-rsync.sh
set -euo pipefail
REMOTE_USER=rsync-user
REMOTE_HOST=nas.local
REMOTE_DATASET=backuptank/clients/server-foo
REMOTE_MOUNT=/backuptank/clients/server-foo
SRC="/etc /home /srv"
HOSTNAME=$(hostname -s)
TS=$(date +%Y-%m-%dT%H-%M-%S)
# 1. 同步过去(增量;--delete 保镜像)
rsync -aAXH --numeric-ids --delete --info=stats2,progress2 \
-e ssh \
$SRC "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_MOUNT}/${HOSTNAME}/"
# 2. 完成后远程 zfs snapshot 标记这一刻
ssh "${REMOTE_USER}@${REMOTE_HOST}" \
"sudo zfs snapshot ${REMOTE_DATASET}@${HOSTNAME}-${TS}"
echo "snapshot: ${REMOTE_DATASET}@${HOSTNAME}-${TS}"
# 3. retention:保留最近 30 个 snapshot
ssh "${REMOTE_USER}@${REMOTE_HOST}" "
sudo zfs list -H -o name -t snapshot ${REMOTE_DATASET} \
| grep '@${HOSTNAME}-' \
| sort -r \
| tail -n +31 \
| xargs -r -n 1 sudo zfs destroy
"
每天 cron / timer 跑这个。
浏览 / 还原历史快照
NAS 上 ZFS snapshot 默认可访问:
ls /backuptank/clients/server-foo/.zfs/snapshot/
# server-foo-2024-05-24T03-00-00
# server-foo-2024-05-23T03-00-00
# ...
# 还原某个文件
cp /backuptank/clients/server-foo/.zfs/snapshot/server-foo-2024-05-24T03-00-00/etc/nginx/nginx.conf /tmp/
或者 zfs clone 把 snapshot 挂成可写副本:
sudo zfs clone backuptank/clients/server-foo@server-foo-2024-05-24T03-00-00 \
backuptank/restore/server-foo-2024-05-24
mount | grep restore
任意时间点的完整目录树都能挂载浏览。
ZFS dedup(可选)
如果多机器备份内容重叠多(OS 文件大体相同):
sudo zfs set dedup=on backuptank/clients
代价:每 1 TB dedup 数据约需 5 GB RAM 维护 dedup table。
所以只在高 dedup ratio + 充裕 RAM 时开。
测:
sudo zdb -S backuptank
# 输出 estimated dedup ratio:1.5x 以上才值得开
ZFS send:异地同步备份
# 第一次全量 → 异地 NAS
sudo zfs send backuptank/clients/server-foo@latest \
| ssh remote-nas "sudo zfs receive backuptank-mirror/server-foo"
# 后续增量
sudo zfs send -i @prev-snap backuptank/clients/server-foo@new-snap \
| ssh remote-nas "sudo zfs receive backuptank-mirror/server-foo"
或者 syncoid 自动:
syncoid backuptank/clients/server-foo remote-nas:backuptank-mirror/server-foo
每天本地 rsync + snapshot;每周 syncoid 异地。两层保护。
与"直接备到 ZFS snapshot" 的对比
替代方案:客户端不 rsync,业务机自己 ZFS snapshot + zfs send 给 NAS。
# 业务机
sudo zfs snapshot tank/data@$(date +%F)
sudo zfs send -i @prev tank/data@new \
| ssh nas "sudo zfs receive backuptank/clients/foo"
优点:
- 原生 ZFS 一致性快照(毫秒级 frozen)
- 增量 send 只传变化的 block(比 rsync 比 file 快很多)
- 文件系统级,不漏 metadata / xattr / hardlink
要求:业务机文件系统是 ZFS。
如果业务机是 ext4 / xfs → rsync + 备份目标 ZFS snapshot 是 fallback。
monitoring
# 看 snapshot 数 + 大小
zfs list -t snapshot backuptank/clients/server-foo
# Prometheus exporter (node_exporter zfs collector)
# 暴露:node_zfs_zpool_state{pool="backuptank"} = 1 (ONLINE)
# node_zfs_zfs_dataset_used_bytes
# node_zfs_zfs_dataset_available_bytes
仪表盘看:
- snapshot 数量是否正常增长
- 各客户端的备份目录大小变化
- 最新 snapshot 时间戳(确认 cron 跑了)
告警:snapshot 超过 26 小时没新 = 备份链断了。
retention 策略:sanoid 风格
手写 tail -n +31 简单但只按计数。sanoid 风格按时间精细:
# 保留:
# - 最近 7 个 hourly
# - 最近 30 个 daily
# - 最近 12 个 monthly
snapshots=$(ssh nas "sudo zfs list -H -o name -t snapshot backuptank/clients/foo")
# 分组按时间删
# (实际写起来复杂;建议用 sanoid 现成工具)
sanoid 配 retention policy + 跨多 dataset 统一管。装好后写一个
sanoid.conf 完事。
实战效果
我们 20 台业务机每天备份到一台 NAS:
| rsync only | rsync + ZFS snapshot | |
|---|---|---|
| 单次备份耗时 | 30 min | 30 min |
| 一致性 | 半天的飘移 | 时刻精确 |
| 历史版本 | 没有 | 30 天日级 |
| 占用空间 | 增量 | 增量 + dedup 后接近 |
| 还原历史文件 | 困难 | cp /.zfs/... |
ZFS snapshot 几乎免费给增量备份"加时间维度"。
与商业方案对比
| rsync + ZFS | Duplicati | restic to S3 | Veeam | |
|---|---|---|---|---|
| 价格 | 免费 | 免费 | 免费 + 存储费 | 商业 |
| 客户端加密 | 否(依靠传输 ssh) | ✅ | ✅ | ✅ |
| 时间点恢复 | ✅(snapshot) | ✅ | ✅ | ✅ |
| Web UI | 无 | 有 | 第三方 | ✅ |
| 学习曲线 | 中 | 低 | 低 | 中 |
家用 / 小公司 + 有 ZFS NAS → 这套最便宜 + 最快。
踩过的坑
-
sudo zfs snapshot没权限:rsync 用户没 zfs allow。
sudo zfs allow rsync-user create,destroy,snapshot ...。 -
snapshot 名字有冲突:同一秒两次备份生成同名 snapshot 失败。
用毫秒级或随机 suffix。 -
--delete删了重要文件:业务机误删 → rsync 同步删 → 但
ZFS snapshot 保住前一刻状态。snapshot 是真正救命。 -
未控制保留 → snapshot 爆:1 年 = 365 个 daily snapshot,
每 snapshot 元数据几 MB → 几 GB 元数据。
sanoid 策略限制数量。 -
NAS 空间满 → 客户端 rsync 失败:监控 ZFS pool 利用率,
超过 80% 告警。
登录后参与评论。