你有多久没真正做过一次恢复演练了?大多数团队的备份策略停留在“每天定时把数据库文件拷走”这一步,至于这些备份能不能用、恢复要花多久、丢了多少数据,没人说得清。这篇文章的作者用 SQLite 搭了一个极简的恢复实验室,把“备份→制造故障→恢复→校验”的完整闭环跑通,并且用 GitHub Actions 把恢复测试嵌进了 CI/CD 流程——每次代码推送都会先验证备份可恢复,才允许部署。这个思路对任何有状态服务的团队都有直接参考价值。

先定义清楚:什么才算“恢复成功”

作者开篇就点破一个反常识的事实:**一文件夹的备份文件并不能证明你的应用能恢复**。要验证恢复能力,必须主动制造一次受控的数据丢失,然后从备份里恢复,再核对恢复出来的数据是不是你期望的样子。

这里引入了两个关键指标:**RPO**(Recovery Point Objective,恢复点目标)和 **RTO**(Recovery Time Objective,恢复时间目标)。RPO 回答“我们能容忍丢多少数据”——比如你备份之后又录入了一笔销售记录,那么从备份恢复,这笔记录必然丢失;RTO 回答“恢复要花多久”——包括找到备份、准备环境、启动应用、验证数据这一整套动作的时间。这两个指标不是理论概念,在这个实验室里,你可以在几十条记录的小数据集上直观地看到它们如何运作。

ANTONY PIERO SOLORZANO ZEGARRA
ANTONY PIERO SOLORZANO ZEGARRA

备份策略和格式:不是只有“全量拷贝”一种玩法

备份策略有几种常见选择:**全量备份**保存完整状态,恢复最简单,但成本随数据量线性增长;**增量备份**只保存自上次备份以来的变化,恢复时需要重建整条链;**差异备份**保存自上次全量备份以来的变化,恢复时只需要全量加最近一次差异。这个实验室只实现了全量备份,没有碰增量、差异和基于日志的时间点恢复。

除了策略,还有**物理备份**和**逻辑备份**之分。物理备份直接复制数据库文件,保留所有物理细节;逻辑备份导出 SQL 语句,重建表结构和数据,但不保留文件层面的物理属性。作者在 Python 里两种都做了:用 `Connection.backup()` 创建物理备份,用 `iterdump()` 生成 SQL dump。

这里有个容易踩的坑:直接复制一个正在写入的数据库文件,可能得到一份损坏或不完整的副本。SQLite 提供了 **Online Backup API** 和 `VACUUM INTO` 两种安全方案。特别要注意的是,如果启用了 **WAL**(Write-Ahead Logging,预写日志,SQLite 的一种并发控制机制,写入先记日志再落主文件),主文件里可能并不包含所有已提交的事务,所以不能简单地把主文件拷走当备份。作者选择用 Online Backup API。

pic
pic

一个可复现的恢复演练:3 条记录走完全流程

整个实验室不需要任何第三方依赖,一条命令就能跑:`python3 backup_demo.py --output lab-results`。程序会创建三个虚构商品,做一次备份,计算 SHA-256 校验和,生成 SQL dump,然后清空这个可丢弃的库存表,再从备份恢复。

核心操作就两行代码:备份时 `live.backup(snapshot)`,恢复时把源和目标对调。恢复之前先校验备份文件的 SHA-256,恢复之后对比记录是否和原始数据一致,同时还会从 SQL dump 在内存里重建一个数据库做逻辑恢复验证。最终报告会显示初始行数、事故后行数、恢复后行数以及完整性检查结果。

实际跑出来的结果是:3 条记录 → 事故后 0 条 → 恢复后 3 条,`integrity_check` 通过,逻辑恢复也正确。GitHub Actions 会在每次部署前自动重跑这个测试。

浏览器里的备份演示:让非技术人员也能看懂 RPO

作者还做了一个网页版演示,用的是 **sql.js**(一个把 SQLite 编译成 WebAssembly 在浏览器里运行的库)。页面流程很直观:先给三个商品做备份,然后新增第四条记录,接着模拟故障把库存清空,最后恢复备份——你会发现那三条备份时的记录回来了,第四条新增的没了。这就是 RPO 的直观体现:备份之后写入的数据,恢复时必然丢失。

这个网页版演示的架构也很有意思:SQLite 完全跑在访问者的浏览器里,没有共享的数据库服务器,也没有远程备份服务。你可以把备份文件下载成 .sqlite 文件,但页面刷新后内存里的数据就没了。GitHub Pages 只托管静态界面。

Jessica Doering profile image
Jessica Doering profile image

把恢复测试嵌进 CI/CD:备份验证成为部署前置条件

仓库里的 `.github/workflows/pages.yml` 定义了一个工作流:每次 push 到 main 分支,先跑恢复测试,只有测试通过才把 `site/` 目录发布到 GitHub Pages。这个工作流也可以手动触发。配置时只需在仓库设置里把发布源选为 GitHub Actions 即可。

整个流程不需要在代码里硬编码任何密码或个人 token,用的是 Actions 的临时权限。部署是自动的,浏览器里的备份是用户点击按钮时创建的——这是两个完全独立的过程。

Juber Shaikh profile image
Juber Shaikh profile image

校验不等于安全,备份要存到异地

SHA-256 校验能检测文件是否被篡改,但前提是你的参考哈希值本身可信——如果攻击者能同时替换备份文件和哈希值,校验就形同虚设。`PRAGMA integrity_check` 只检查数据库结构完整性,而对比记录才能验证业务数据是否正确。这些手段都不能替代真实应用的功能性测试。

作者建议生产环境遵循 **3-2-1 备份策略**:三份副本、两种不同存储介质、一份存放在异地。同时要限制权限、加密备份、定期做恢复演练。这个实验室的备份和数据库在同一个内存里,显然不满足 3-2-1 要求。

关于保留策略,应该根据 RPO 来定:比如每天备份保留 7 天,每周备份保留 4 周,具体按业务需求调整。这个项目本身没有实现保留策略。

Hemapriya Kanagala profile image
Hemapriya Kanagala profile image

这个思路能用到哪里

最直接的借鉴是:**把“恢复测试”变成 CI/CD 流水线的一个标准步骤**。不管你的数据库是 PostgreSQL、MySQL 还是 MongoDB,都可以在测试环境里做一次真实的备份恢复演练,验证备份文件可用、恢复流程可执行、数据完整性可校验。另一个启发是,**用最小可复现的实验室来验证一个复杂概念**——作者用 3 条记录就把 RPO/RTO、物理/逻辑备份、在线备份 API 这些概念讲清楚了,这种“先跑通最小闭环,再谈生产化”的思路,适合用来验证任何基础设施方案。

要注意的坑是:别把“能生成备份文件”当成“能恢复”。备份只是起点,找到它、恢复它、验证它,才是终点。

DEV Community
DEV Community
阅读原文 → 返回 AI 技术文档

内容与图片版权归原作者所有 · 原文: https://dev.to/antonys3010/un-backup-sirve-cuando-puedes-restaurarlo-laboratorio-con-sqlite-y-github-actions-3i4p