3. 快照技术原理深入

要真正理解快照为什么“快”、为什么“省空间”、又为什么在某些场景下会不一致,必须把快照从“功能”还原为“机制”。快照的本质不是复制数据,而是在某个时间点对数据建立一种可回溯的引用关系。Pure Storage FlashArray 上的快照(Purity 中称为 Snapshot)之所以能在毫秒级完成、且几乎不占用额外空间,关键在于它操作的是元数据,而不是数据本身。

一、写时重定向:快照的“不复制”哲学

传统存储常用写时复制(Copy-on-Write, CoW):当某个数据块即将被覆盖时,先把旧数据搬到别处保存,再写入新数据。CoW 的代价是每次写都可能触发一次额外的读+写,写放大明显。Pure Storage 采用的是写时重定向(Redirect-on-Write, RoW),思路正好相反:旧数据原地不动,新写入被重定向到新的数据块,然后只更新元数据指针。

用一个具体例子说明。假设卷 Vol-A 有一个 4 KB 数据块 D0,被快照 S1 引用。此时应用要覆盖 D0:

  • CoW 路径:读出 D0 → 写入新位置 D0'(保留给 S1)→ 再把新数据写入 D0 原位置。一次写变成“读+两次写”。
  • RoW 路径:新数据直接写入一个空闲块 D1 → 更新 Vol-A 的元数据指针,使其指向 D1 → D0 保持不动,仍由 S1 引用。一次写就是一次写。

因此 RoW 的写放大接近 1,快照创建时也无需复制任何数据块,只需记录“当前元数据树的根”。这就是快照能在瞬间完成、且对生产性能几乎无影响的根本原因。

写时重定向(RoW):旧块不动,新写重定向 ① 创建快照 S1 ② 应用覆盖 D0 ③ 读 S1 / 读 Vol-A 创建 S1 时 D0 ← Vol-A 与 S1 共享 仅记录元数据根,无数据复制 覆盖 D0 时 D0 D1(新) 新数据写入 D1,指针重定向 读取结果 D0 D1 S1→D0(旧) Vol-A→D1(新) 元数据指针变化(逻辑视图) Vol-A 指针: D0 ──覆盖后──▶ D1 S1 指针: D0 ──保持不变──▶ D0 关键:D0 从未被移动或复制,仅 Vol-A 的引用被改写;S1 因此“冻结”了旧数据。

二、元数据快照:快照树与共享块

FlashArray 的卷由一棵元数据树描述:根节点指向若干间接块,间接块再指向数据块。创建快照时,Purity 并不复制这棵树,而是复制根指针并置为只读,形成“快照树”。此后生产卷继续写入时,RoW 机制让新旧两棵树逐渐分叉:未被修改的块由两棵树共享,被修改的块则各自指向不同数据块。

这种结构带来两个重要特性。第一,快照之间可以共享块:如果 S1 和 S2 都创建于 D0 被修改之前,它们都指向 D0,物理上只有一份。第二,快照可以级联:S2 基于 S1 创建时,只需记录 S1 的根,形成父子链。删除中间快照时,Purity 通过引用计数判断哪些块仍被其他快照引用,只有引用计数归零的块才会被回收。

三、空间效率:共享、去重与引用计数

快照的空间开销取决于“分叉程度”,而不是快照数量。假设一个 1 TB 卷,每天创建一个快照,每天变化率 5%:

项目数值(示例)说明
卷容量1 TB逻辑容量
日变化率5%假设均匀覆盖
单快照新增物理块约 50 GB仅变化部分产生新块
7 个快照累计新增约 350 GB未变化块持续共享
若用全量克隆7 TB对比:空间放大 20 倍

需要强调:以上为教学示例参数,实际占用还受去重、压缩、块对齐和写入模式影响。FlashArray 的全局去重与压缩会进一步降低物理占用,但快照本身的“省”首先来自块共享,其次才是去重压缩。引用计数是安全回收的基础:只有当某数据块不再被任何卷或快照引用时,空间才会真正释放。

四、一致性组:把多个卷“绑”在同一时间点

数据库、虚拟机集群等场景往往跨多个卷。如果分别对每个卷打快照,即使间隔只有几毫秒,也可能落在不同的写入时刻,恢复后卷间关系错乱。一致性组(Consistency Group, CG)解决这个问题:它把多个卷作为一个原子单元,在同一时刻为组内所有卷创建快照,并保证组内快照具有相同的逻辑时间点。

在 Purity 中,一致性组快照的创建同样是元数据操作:先短暂冻结组内写入(或利用写顺序屏障),再统一复制各卷的元数据根。由于不复制数据,冻结窗口极短,通常对应用透明。恢复时,整个组一起回滚,保证跨卷引用完整性。

五、崩溃一致性 vs 应用一致性

即使一致性组保证了“同一时刻”,快照仍可能处于崩溃一致性(Crash Consistency)状态:它相当于把服务器电源突然拔掉那一刻的磁盘状态。此时文件系统日志、数据库事务日志可能尚未落盘,恢复后需要重放日志或做一致性检查。

要获得应用一致性(Application Consistency),必须在打快照前让应用进入静默状态:

  1. 通知数据库执行 FLUSH TABLES WITH READ LOCK 或进入备份模式,将内存脏页刷盘;
  2. 确认日志与数据文件处于一致点;
  3. 触发一致性组快照;
  4. 立即解除应用静默,恢复业务写入。

Pure Storage 通过 Pure Storage FlashArray 的 Protection Group 与快照计划,配合应用侧脚本或 VSS/ODX 等集成,实现这一“静默—快照—解静默”的闭环。若省略静默步骤,快照仍可用,但恢复后可能需要额外修复,RTO 会变长。

判断快照是否满足需求,可以问三个问题:时间点是否统一(一致性组)、应用是否静默(应用一致性)、空间是否可回收(引用计数与保留策略)。三者分别对应机制、流程与生命周期管理。

理解这些底层机制后,后续配置快照计划、设置保留策略、设计恢复流程时,就能清楚每一步在元数据层面发生了什么,也能预判空间增长与恢复行为,而不是把快照当成一个黑盒按钮。