收起左侧

对自动化文件快照的思考

2
回复
100
查看
[ 复制链接 ]

4

主题

7

回帖

20

牛值

社区共建团

本文诞生于笔者使用 TrueNAS, 群晖 DSM, 飞牛OS 的过程中。文件系统如何实现 CoW 和快照是个技术难题,但是如何利用快照技术实现数据保护,依然需要用户做很多思考。为此,笔者写下了这篇文章。

考虑到飞牛目前的 ZFS 快照/replication 还处于一个非常初级的阶段,因此本文也适合飞牛的开发者参考。


坑边闲话:绝大多数人都听过「3-2-1 备份原则」:至少三份数据,存储在两种不同介质上,其中一份存放在异地。然而,即使在真正理解这一原则的人群中,数据丢失的案例依然层出不穷。原因很简单:他们只有备份意识,却没有备份系统;只有备份习惯,却没有自动化策略。本文以 ZFS 为底层文件系统,讲解备份过程中的内功心法。如果你使用的是其他类型的 CoW 文件系统如 BtrFS,应该也能从中获益。

现实中最危险的情况并不是“没有备份”,而是:

  • “我打算做备份,但还没开始。”
  • “我上个月备份过一次,应该没问题。”
  • “我桌面同步到 NAS 了,也算备份吧?”
  • “我准备找时间再备一下。”

一旦出现硬盘损坏系统崩溃勒索病毒用户误删手动备份都是苍白无力的。只有当备份方案具备以下特征时,数据才真正安全:

  • 自动化:不依赖人的意志;
  • 低开销:不打扰日常工作,不占用过多资源;
  • 可验证:快照、校验机制确保备份有效;
  • 可逆转:恢复流程清晰,不需要人临时拼命抢救。

换句话说:

  • 可靠的备份不是“记得备份”,
  • 而是“就算你忘了,系统也会替你记得”。

1. 备份的内功心法

本来笔者打算花大量篇幅介绍 zrepl 的使用方案,并像往常一样给出备份 yaml 配置文件作为最佳实践。然而,在学习了大量 zrepl 的设计细节之后,笔者发现这样的文章将会非常长,而且阅读难度相当高,非常不利于新用户上手使用 zrepl 这个极为强大的备份工具。为此,笔者打算先从一个基本的 YAML 配置文件入手,帮助你厘清为什么 zrepl 选择了这样的设计。

当你学会使用这个最基本的模板之后,后期可以自行探索更高级的语法。

1.1 备份案例呈现

ZFS 的 replication,即 zfs send | zfs receive 基于标准数据流,因此 zfs send 可以重定向到文件,zfs receive 也可以从文件、网络流中接收。当然,这也给程序员提供了无限的想象空间,我们可以基于高性能传输标准构建更强大、更安全的网络协议,在更短时间内、更安全的隧道中实现可靠的 ZFS replication. 然而,笔者今天不打算介绍这一部分,因为这并不是备份的核心要点。

下面是笔者常用的本机备份配置文件。所谓本机备份,就是从本机的 pool_1 获取数据,然后 发送到 pool_2,这当然不属于「3-2-1 备份原则」,因为数据依然只在一台机器上,没有实现真正的异地备份。不过,这个配置文件可以将:

  • source 的快照策略
  • source、sink 的快照保留策略

等核心概念讲清楚。

**s:
  - type: sink
    name: "local_sink"
    root_fs: "Solidigm_P44Pro_Stripe"
    serve:
      type: local
      listener_name: localsink

  - type: push
    name: "gtr7-debian_backup"
    connect:
      type: local
      listener_name: localsink
      client_identity: local_backup
    filesystems: {
      "zroot<": true,
      "Samsung_990Pro_Stripe<": true,
    }
    snapshotting:
      type: cron
      cron: "*/5 * * * *" 
      prefix: zrepl_
      timestamp_format: "human"
    pruning:
      keep_sender:
      - type: not_replicated
      - type: last_n
        count: 72
      keep_receiver:
      - type: grid
        grid: 1x1h(keep=all) | 24x1h | 35x1d | 6x30d
        regex: "zrepl_.*"

1.2 发送与接收

一次成功的 ZFS replication,本质上由两个动作构成:

  • 发送者执行 zfs send
  • 接收者执行 zfs receive

听起来简单,但现实情况比这复杂得多,不同工具在“谁负责 send / receive”以及“控制权在哪里”都有完全不同的设计哲学。

1.2.1 TrueNAS:集中化、NAS 主导的 replication 模型

以 TrueNAS 的 Replication Task 为代表,它将所有决策和命令执行权都集中在 NAS 本体上。

TrueNAS 的基本流程:

  • 首先根据任务类型判断:
    • Pull:NAS 主动去远端拉取快照(NAS 调用远端的 zfs send)
    • Push:NAS 主动向远端推送快照(NAS 本地执行 zfs send)
  • 根据任务类型,TrueNAS 会通过 SSH 在远端执行必要命令,典型流程是:
    • 在远端执行 zfs send
    • 在本地执行 zfs receive(或反之)

TrueNAS 的优点:

  • 无需在客户端系统上安装任何软件
  • 只要客户端上:
    • 开放 ssh
    • 拥有自己的 snapshot

NAS 就能完成整个备份流程。然而,TrueNAS 的方案也有很多弊端。

TrueNAS 理论上可以远程调用 zfs snapshot <ds>,但它没有实现,原因就在于 SSH 是远程调用,存在延迟与阻塞,无法保证 snapshot 的实时性与一致性。此外,同一台 TrueNAS 对数百个客户端下发快照命令时,由于并发量限制,难以维持精准的实时性。因此,

  • 客户端系统必须自行创建 / 管理自己的快照,
  • NAS 只能基于已有的快照执行 replication.

这一点,也让 TrueNAS 在“多客户端、大规模环境”下显得不够优雅。

1.2.2 zrepl:分布式、端到端自动化的现代 replication 模型

与 TrueNAS 完全不同,zrepl 采用的是分布式架构。在跨主机 replication 场景中,zrepl 要求参与系统都必须安装 zrepl. 这看似成本更高,但实际上带来巨大的工程优势:

  • 每台机器都能自动地
    • 创建快照
    • 管理快照生命周期
    • 执行 send
    • 执行 receive
  • 所有的 snapshot、pruning、replication 全部通过 zrepl agent 处理

也就是说,zrepl 从 NAS 主导式备份升级为「分布式备份管控系统」。为什么这更强?因为 zrepl 避免了 SSH 远程调用的弊端:

  • snapshot 可以由本机 zrepl agent 直接执行(毫秒级)
  • send/receive 自动根据带宽、快照链、resume token 等自动协调
  • prune(保留策略)可在 sender 和 receiver 侧分别执行
  • 不会因为网络延迟错失 snapshot,或执行时机不准确

此外,zrepl 几乎为所有 Linux 发行版、甚至 FreeBSD 都提供了官方安装包。这意味着:Debian、Ubuntu、Arch、RedHat 等系统均可原生部署,远比 TrueNAS 的 SSH 远程操控模型更适合集群、分布式备份、实验室、多池架构等场景。

1.3 精简的快照策略

zrepl 的快照策略乍看非常简单:只需要配置一个高频快照任务即可。但这背后依赖的是 zrepl 强大而灵活的快照保留 (pruning) 机制。

与此形成鲜明对比的是 TrueNAS 等系统的快照机制。它们依赖传统的 cron 式定时任务,为了实现“近期稠密、远期稀疏”的快照保留方式,只能采取如下策略:

  • 为同一个数据集设置多个快照任务
  • 每个任务对应不同的周期与保留时间,例如:
    • rule1: 每 5 分钟一次,保留 2 小时
    • rule2: 每 1 小时一次,保留 24 小时

然而这种方式带来了许多工程层面的麻烦。如果两个快照任务采用相同的命名规则,那么在时钟的整点,5 分钟策略会触发,1 小时策略也会触发,而创建同名 ZFS 快照会引发系统报错。为避免冲突,TrueNAS 官方建议:

  • 方案 A: 为快照任务设置不同的命名规则
  • 方案 B: 调整任务执行时间,例如偏移 2 分钟

但这两种做法都不够优雅:

  • 方案 A:时间偏移

    • 快照时间不再与整点、整分对齐
    • 不利于排查时间线
    • 不符合大多数人习惯的时间结构
  • 方案 B:不同命名规则

    • 两个几乎完全相同的快照被重复创建
    • 快照数量无意义增加
    • 写入性能下降,快照太多会导致 ARC/metadata 压力。ZFS 行为决定了快照越多,写入越慢。无意义的快照应该尽量避免。

zrepl 的做法是让快照生成与保留策略解耦。为此,zrepl 采用了完全不同的理念:只需要一个高频拍摄策略。例如每 5 分钟拍一次:

# periodic 意味着从 zrepl 服务启动开始,周期性执行快照任务
snapshotting:
    type: periodic
    interval: 5m
    timestamp_format: "human" # 时间为 UTC 时区,human 格式更容易读懂

# periodic 有可能不是钟表刻度整分对齐,因此还可以使用更规整的 cron 策略
snapshotting:
    type: cron
    cron: "*/5 * * * *" # 同样是 5 分钟执行一次
    prefix: zrepl_
    timestamp_format: "human"

「近期稠密、远期稀疏」原则由 pruning (保留策略) 自动实现。zrepl 提供了比 TrueNAS 先进得多的 pruning 规则,例如 grid:

# 如果不写 (keep=?) 就默认 (keep=1), 下一节会详细介绍
grid: 1x1h(keep=all) | 24x1h | 30x1d | 6x30d

这类策略意味着:

  • 最近 1 小时:全保留(每 5 分钟一条)
  • 最近 24 小时:保留小时级快照
  • 最近 30 天:保留每天一个
  • 最近半年:保留每月一个

所有这些都无需额外 snapshot 任务,也不需要不同命名规则,也不会产生时间冲突,更不会产生冗余快照,真正实现了单一任务、多层时间密度、自动演化。

总结:TrueNAS 依赖多个定时快照任务组合策略,复杂且容易冲突;zrepl 依赖单一高频快照加强大的 pruning 策略,简单却极度灵活。

这也是为什么:

  • TrueNAS 的快照体系是基于时间的触发机制
  • zrepl 的快照体系是基于事件与生命周期的链式机制

两者不仅在技术细节上不同,在架构设计上就完全不是一个时代的产物。

收藏
送赞
分享

4

主题

7

回帖

20

牛值

社区共建团

前天 20:00 楼主 显示全部楼层

晚些更新 zrepl 设计哲学中的

  • 无数据库原则,一切信息来自 ZFS,而不是用自己的任何数据库
  • status 状态检查
  • grid 时间筛模型

7

主题

33

回帖

0

牛值

初出茅庐

技术贴,不明觉厉lol

[img]https://cdn.jsdelivr.net/gh/master-of-forums/master-of-forums/public/images/patch.gif[/img]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则