备份的价值不在于「我有一份」,而在于「我能在需要的时候,用它恢复到一个可用的状态」。前者是存储,后者才是备份。
一、误删之后的四十八小时
这是为解释机制构造的假设案例,人物、引语、收入和耗时均为教学设定,不是对真实事件的调查记录。
一位开发者给自己的 SaaS 做数据库清理,想删掉测试环境里的一张表。终端窗口开在两个标签页,他删掉的是生产环境。
数据库开启了每日自动备份,保留 30 天。看起来没问题。但恢复时他发现:
- 自动备份和数据库在同一个云账号、同一个区域。
- 备份是「实例级快照」,恢复只能整实例恢复到某个时间点,不能只恢复一张表。
- 他需要把整个实例恢复到一个新实例,再从新实例导出数据,最后导回生产。
- 整个过程他做过一次,但那是两年前,步骤已经忘了。
四十八小时后,数据恢复了。丢的是最后一次快照之后的几个小时订单。他说:
「我有备份,但我没有恢复能力。这两件事之间,差了一次演练。」
二、3-2-1 与 3-2-1-1-0
2.1 经典 3-2-1
| 数字 | 含义 | 个人产品的落地 |
|---|---|---|
| 3 | 至少三份数据 | 生产 + 备份 + 归档 |
| 2 | 至少两种介质 | 云存储 + 本地硬盘 / 对象存储 + 磁带 |
| 1 | 至少一份异地 | 不同区域或不同供应商 |
2.2 增强版 3-2-1-1-0
| 数字 | 含义 | 为什么重要 |
|---|---|---|
| 3 | 三份数据 | 防单点丢失 |
| 2 | 两种介质 | 防同一类介质同时损坏 |
| 1 | 一份异地 | 防区域性故障 |
| 1 | 一份离线或不可变 | 防勒索软件与误删同步 |
| 0 | 零错误,经过验证 | 防「备份存在但不可用」 |
最后两个数字是个人产品最容易漏掉的。离线/不可变防的是「攻击者或你自己把备份也删了」;零错误防的是「备份文件损坏、权限不对、恢复脚本失效」。
三、按数据分级定 RPO/RTO
不是所有数据都值得同样的投入。先分级:
| 数据等级 | 内容 | RPO | RTO | 备份方式 |
|---|---|---|---|---|
| A:不可再生 | 用户数据、订单、支付记录、许可证 | ≤ 1 小时 | ≤ 4 小时 | 持续归档 + 时间点恢复 |
| B:业务关键 | 配置、内容、邮件、分析数据 | ≤ 24 小时 | ≤ 24 小时 | 每日全量 + 增量 |
| C:可重建 | 缓存及已证明可重建的数据 | 业务可接受的丢失范围 | 已测得重建时间 | 发布产物、审计日志如不可重建则另分级 |
| D:合规保留 | 审计日志、发票、合同 | 不丢失 | 可检索 | 归档存储,长期保留 |
先写 A 级数据的 RPO/RTO,再决定备份频率。 如果 A 级 RPO 是 1 小时,每日一次的全量备份就不合格。
四、备份对象清单
很多人的备份只覆盖数据库,漏掉了「恢复时必须一起回来」的东西。
| 对象 | 常见位置 | 备份方式 | 备注 |
|---|---|---|---|
| 关系型数据库 | 云数据库 / 自建 | 快照 + 逻辑导出 + WAL/binlog | 逻辑导出用于单表恢复 |
| 对象存储 | 具体桶及供应商 | 核验该产品的复制、版本/保留能力,另留独立副本 | S3 兼容接口不代表能力相同 |
| 配置文件 | 环境变量 / 配置中心 | 加密导出 | 与代码分开存放 |
| 密钥与证书 | 密码管理器 / KMS | 离线加密副本 | 不要只存在一个 KMS |
| 日志 | 日志服务 | 归档到冷存储 | 事故取证需要 |
| 许可证与订单 | 支付平台 / 自建 | 定期导出 CSV | 平台受限时的对账依据 |
| 邮件 | 邮箱服务商 | 定期导出 mbox | 客户沟通与合同证据 |
| DNS 区域 | DNS 托管商 | 导出区域文件 | 换托管商时必需 |
| 分析数据 | 分析平台 | 定期导出 | 避免平台锁定 |
五、备份方式的选择
| 方式 | 优点 | 缺点 | 适用 |
|---|---|---|---|
| 实例快照 | 快、完整、可整机恢复 | 粒度粗、跨区域可能额外收费 | A 级数据的日常保护 |
| 逻辑导出 | 可单表恢复、可跨版本 | 慢、占空间、恢复需重建 | 迁移与单表修复 |
| 时间点恢复(PITR) | 可恢复到秒级 | 依赖 WAL/binlog 保留 | A 级数据的兜底 |
| 文件同步 | 简单 | 误删会同步、可能被加密 | 不适合作为唯一备份 |
| 对象存储版本控制 | 防覆盖与误删 | 需要管理生命周期 | 文档、配置、产物 |
| 离线硬盘 | 隔离性好 | 需要人工、易忘记 | 年度归档 |
至少组合两种。 例如:云数据库快照(日常)+ 每日逻辑导出到另一个账号的对象存储(可单表恢复)+ 每月离线归档(防勒索与误删)。
六、加密与密钥分离
备份里往往包含用户数据、密钥、合同。加密是必须的,但加密方式决定你能不能在事故中恢复。
6.1 三条原则
- 备份加密,传输加密,存储加密。 三者不是一回事。
- 加密密钥不要和备份放在同一个地方。 备份在云 A,密钥至少在云 B 或离线。
- 密钥丢失等于备份丢失。 密钥也要有恢复副本,且要有人知道怎么用。
6.2 常见结构
| 结构 | 密钥存放 | 风险 |
|---|---|---|
| 云厂商托管密钥 | 同一云账号的 KMS | 账号失守,备份与密钥一起没 |
| 自管密钥 + 云存储 | 密码管理器 / 离线 | 密钥丢失则无法恢复 |
| 客户端加密后上传 | 本地密钥 + 离线副本 | 操作复杂,容易忘 |
个人产品推荐第二种:备份上传前在客户端加密,密钥存密码管理器并留一份离线。 这样云厂商看不到明文,账号失守也不至于直接泄露数据。
七、不可变与删除保护
勒索软件和误操作的第一反应都是「删备份」。所以备份系统要能抵抗「有权限的人删除」。
| 机制 | 作用 | 注意 |
|---|---|---|
| 对象存储版本控制 | 保留历史版本 | 需要设置生命周期,避免无限增长 |
| 对象锁(Object Lock) | 在保留期内不可删除 | 选合规模式还是治理模式要清楚 |
| 快照保留策略 | 防止快照被批量删除 | 保留策略本身也要保护 |
| 跨账号复制 | 生产账号失守不影响备份账号 | 备份账号不要用同一组凭据 |
| MFA 删除 | 删除需要第二因素 | 紧急时可能阻碍恢复 |
| 离线副本 | 物理隔离 | 需要定期更新 |
最低要求:备份存储在一个与生产不同的账号,且生产账号的凭据不能删除备份。
八、恢复演练:每季度一次
没有演练的备份,只能算「希望」。
8.1 演练清单
- 选一个 A 级数据对象(例如订单表)。
- 从备份恢复到一个隔离环境,不影响生产。
- 记录开始时间、恢复完成时间、数据截止时间。
- 校验行数、关键字段、金额合计。
- 记录遇到的权限、版本、依赖问题。
- 更新恢复手册。
- 把演练结果写进日历,下次继续。
8.2 演练指标
| 指标 | 计算 | 目标 |
|---|---|---|
| 实际 RTO | 恢复完成时间 − 发现时间 | ≤ 设定目标 |
| 实测数据损失窗口 | 故障时点 − 可恢复的一致性业务截止点 | 与 RPO 目标比较;非单看最大时间戳 |
| 一次成功率 | 第一次尝试即恢复成功 | 尽量为 1 |
| 人工步骤数 | 需要手动执行的步骤 | 越少越好 |
8.3 三种演练场景
| 场景 | 验证什么 |
|---|---|
| 单表误删 | 逻辑导出是否可用、恢复粒度是否够细 |
| 整库损坏 | 快照 + PITR 是否可用、跨区域恢复是否可行 |
| 账号失守 | 备份账号是否独立、凭据是否隔离 |
九、成本控制
备份会持续花钱。三个控制手段:
- 分层存储:最近 30 天用标准存储,3 个月后转低频,1 年后转归档。
- 保留策略:示例可为可恢复运行数据保留 90 天、一般配置 30 天;法定会计档案、合同证据和隐私删除须分别确定,不能由 A/B/C 标签自动决定。
- 去重与压缩:逻辑导出时压缩,快照利用云厂商的增量能力。
不要为了省钱砍掉「异地」和「离线」。这两项恰恰是事故时最值钱的。
十、常见错误
| 错误 | 后果 | 更好的做法 |
|---|---|---|
| 备份与生产同账号 | 账号失守,备份一起没 | 跨账号、跨供应商 |
| 只做快照,不做逻辑导出 | 无法单表恢复 | 快照 + 逻辑导出组合 |
| 备份加密密钥存在同一云 | 账号失守即无法解密 | 密钥存密码管理器 + 离线 |
| 从不校验备份 | 真恢复时发现文件损坏 | 每次备份计算校验和 |
| 从不演练 | 不知道恢复要多久、缺什么 | 每季度一次计时演练 |
| 备份保留期太长或太短 | 成本失控或恢复点不足 | 按数据等级设保留策略 |
十一、行动清单
- 给数据分级,写出 A 级数据的 RPO/RTO。
- 列出所有需要备份的对象,填进清单。
- 确认备份不在生产账号下。
- 为 A 级数据配置时间点恢复或持续归档。
- 备份加密,密钥与备份分开存放。
- 开启对象版本控制或对象锁。
- 每季度做一次计时恢复演练,记录实际 RTO/RPO。
- 把恢复手册放在能离线打开的位置。
使用边界与实操验收
S3 Object Lock 依赖版本控制并保护指定版本;R2 的 Bucket Locks 是其自身机制,不能直接当作完整 S3 版本控制替代。OSS 也应按其具体版本控制/WORM/复制文档及账号计划核对;本表没有认证三者功能等价。
先填一张桶级能力表:产品/区域/版本是否开启/保留模式/谁可删除或修改策略/独立账号副本/恢复命令/最近演练。对测试对象验证旧版本或保留对象确实能取回,并确认生产凭据不能删除独立副本。
以下 SQLite 夹具演示“自动恢复后做业务一致性校验”,不是云数据库生产备份方案,也未演示备份加密:
import sqlite3
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as d:
d = Path(d)
with sqlite3.connect(d / "source.db") as db:
db.execute("CREATE TABLE orders(id INTEGER PRIMARY KEY, cents INTEGER)")
db.executemany("INSERT INTO orders VALUES(?, ?)", [(1, 1200), (2, 800)])
db.commit()
with sqlite3.connect(d / "backup.db") as backup:
db.backup(backup)
db.execute("DELETE FROM orders")
db.commit()
with sqlite3.connect(d / "backup.db") as backup:
with sqlite3.connect(d / "restored.db") as restored:
backup.backup(restored)
assert restored.execute("PRAGMA integrity_check").fetchone() == ("ok",)
assert restored.execute("SELECT COUNT(*), SUM(cents) FROM orders").fetchone() == (2, 2000)
print("PASS: isolated restore, 2 orders, 2000 cents")
真实演练还需核对对象文件与数据库引用、队列、外键、金额、权限和应用启动;行数相同不等于业务完整。
关键参考与核验范围
以下链接支持对应的机制或规则;本文的案例、成本和经营评分是说明方法的假设,不能当作平台统计或收益承诺。核验日期:2026-10-22。
- S3 Object Lock :保护对象版本及保留机制。
- R2 Bucket Locks :桶级保留规则,不宣称与所有 S3 功能相同。
- Python sqlite3 backup :夹具使用数据库备份 API。
系列导航
- 上一篇:代码与仓库:多远程、组织所有权、镜像与归档
- 下一篇:云账号与账单:根账号、IAM、预算告警与供应商锁定
- 回到目录:独立开发者的资产韧性
- 相关阅读:可观测性与错误追踪 、SaaS 事故沟通
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。