校验的三个阶段
一句话总结
备份验证分为是否存在 → 是否可读 → 是否能恢复三步。前两步可以自动化,最后一步必须由人完成。
为什么需要它
备份每天都在运行,日志也显示成功。可真正需要恢复的那天,文件却打不开。这种情况并不少见。
如何运作
第 1 步 — 是否存在
这是最基本的一步,但很多问题意外地就在这里被发现。
ls -lh /backup/prod/ | tail -5
find /backup/prod -type f -mtime -1 | wc -l
确认文件大小不为 0,并且时间足够新。让监控检查**“最近一次成功是否在 24 小时内”**,远比人工阅读日志可靠。
第 2 步 — 是否可读
检查压缩完整性和归档目录。
gzip -t /backup/etc-2026-08-20.tar.gz && echo 'gzip OK'
tar -tzf /backup/etc-2026-08-20.tar.gz > /dev/null && echo 'archive OK'
sha256sum -c /backup/checksums.sha256
三条命令检查不同内容。gzip -t 检查压缩流 CRC,tar -t 检查归档结构,sha256sum -c 检查整个文件的哈希。可能出现压缩流正常但 tar 结构损坏的情况,反之亦然。
第 3 步 — 是否真的能够恢复
只有这一步才是真正的验证。 在另一台主机或临时环境中恢复并启动服务,然后确认数据属于预期时间点。
演练检查清单如下。
- 访问备份存储的凭据是否保存在生产服务器之外
- 恢复流程文档是否保存在恢复负责人笔记本以外的位置
- 恢复所需的加密密钥是否单独保管
- 演练实测时间是否满足 RTO
- 恢复后应用是否能启动并通过一致性检查
加密密钥的保管尤其容易被遗漏。 如果备份已加密,而密钥只放在被备份服务器上,那么服务器消失时,备份就只是无意义的二进制文件。
恢复演练的现实最低频率是每季度一次。而且应由并非创建备份的人仅凭文档执行,这样才能暴露流程漏洞。
验证脚本的形式
#!/usr/bin/env bash
set -euo pipefail
ARCHIVE="${1:?usage: verify.sh <archive>}"
[ -s "$ARCHIVE" ] || { echo "빈 파일이거나 없음: $ARCHIVE" >&2; exit 1; }
gzip -t "$ARCHIVE" || { echo "압축 스트림 손상" >&2; exit 2; }
tar -tzf "$ARCHIVE" > /dev/null || { echo "아카이브 구조 손상" >&2; exit 3; }
echo "OK $ARCHIVE"
诀窍是为每个阶段设置不同的退出码,这样监控可以立即判断失败发生在哪一步。
现场常见情况
位腐化(bit rot)。 长期保存的归档可能悄悄损坏:磁盘自检仍显示正常,但少数字节已经翻转。定期重新校验 checksum 可以发现它。备份存储使用 ZFS 或 Btrfs 的原因之一,就是它们带有自身校验和。
磁带/对象存储的静默失败。 写入操作返回成功,但数据实际上没有保存。需要在写入后立即读回验证。
3-2-1 为何今天仍然有效
虽然是旧规则,但在云环境中仍然适用。
사본 3개 · 매체 2종 · 오프사이트 1개
如今通常还会补充两条。
- 其中 1 份离线或不可变(immutable) — 勒索软件连备份一起加密已是标准手法。应至少有一个像 Object Lock 的 COMPLIANCE 模式那样,连管理员也无法删除的副本。
- 0 份未经验证的副本 — 未检查的备份不能算作副本。
第二条正是本模块的重点。与其炫耀备份数量,不如确认是否至少有一份实际恢复过的备份。
自动化完整性验证
依赖人工记忆的验证迟早会停止。应自动运行三个层次。
# 1) 파일이 온전한가 — 매일
sha256sum -c backup-2026-09-06.sha256
gzip -t backup-2026-09-06.sql.gz # 압축 무결성만 확인(빠르다)
# 2) 읽을 수 있는가 — 주마다
pg_restore --list backup.dump > /dev/null # 목록만 뽑아 본다
# 3) 복원되는가 — 분기마다
pg_restore -d verify_db backup.dump && psql verify_db -c "select count(*) from orders"
第 1 层需要几秒,第 2 层需要几分钟,第 3 层需要几小时。按成本设置不同周期才是实践中的答案。三层都不做,最后只剩下“有备份”的信念。
在哪里记录验证结果
验证失败却无人知晓,就等于从未验证。需要具备三项内容。
- 指标 — 用 gauge 导出最后成功时间。当
time() - last_success > 2일时告警。相比失败次数,距上次成功所经过的时间才是更准确的信号。 - 记录 — 记录何时、对什么、以什么方式验证,以及结果如何。审计会要求这些信息。
- 告警 — 为备份本身失败和验证失败设置不同告警,因为原因和处置方式不同。
# 백업이 돌지 않는다 (심각)
time() - backup_last_success_timestamp > 86400 * 2
# 백업은 도는데 검증이 실패한다 (더 심각 — 있다고 믿었던 것이 없다)
backup_verify_success == 0
第二种情况更严重。备份没有运行很容易察觉,而看似在运行、实际却无法使用的状态,往往要到真正需要时才会被发现。
下一次实验要做什么
创建校验和清单,人为制造损坏并检测它,再编写带分阶段退出码的验证脚本。评分器会分别用正常归档和损坏归档运行该脚本。