阅读提要

每天自动备份、备份文件大小正常、校验也通过——真出事时才发现恢复出来的库缺了最新数据。没恢复过的备份,只能算一份心理安慰。

开始阅读

字号

一个真实的反例

某站点的备份脚本是这样的:

cp /opt/blog/data/blog.db /backup/blog-$(date +%F).db

每天跑,文件大小看起来也正常。直到某次误删数据要恢复,才发现:恢复出来的库比线上少了最近三个月的数据。

原因很简单:SQLite 开了 WAL 模式,最新的提交还在 -wal 文件里,cp 主库文件只拿到了旧的快照。

这个案例说明一件事:备份的验收标准不是「文件存在」,是「能恢复出可用数据」。

可恢复性检查

先定义两个指标

RPO(恢复点目标):最多能接受丢多少数据。每天备份一次,RPO 就是 24 小时——最坏情况丢掉一整天的数据。

RTO(恢复时间目标):从发现故障到服务恢复,最多允许多久。这决定了你用冷备份还是热备、要不要预置恢复脚本。

这两个数字必须由业务方定,不是技术团队拍。一个博客的 RPO 可能是 24 小时,一个订单系统的 RPO 是 0。

备份的三种正确姿势

文件级冷备份:停服务,复制文件,启服务。一致性最好,但有停机窗口。

逻辑备份:sqlite3 .dump 或 pg_dump。跨版本兼容性好,但慢,且大库恢复时间长。

在线一致性备份:用数据库自带的 API。SQLite 是 backup API,MySQL 是 --single-transaction,PostgreSQL 是 pg_basebackup。不停机、一致性有保证。

对 SQLite,正确写法是:

sqlite3 /opt/blog/data/blog.db ".backup '/backup/blog-$(date +%F).db'"

.backup 走 backup API,会把 WAL 里的内容一起考虑进去。这比 cp 可靠得多。

校验:三个层次

第一层:文件完整性。 SQLite 用 PRAGMA integrity_check;PostgreSQL 用 pg_verifybackup。

sqlite3 /backup/blog-2026-11-01.db "PRAGMA integrity_check;"
# ok

第二层:结构完整。 表数量、关键表的行数是否符合预期。备份出一个空库但 integrity 也是 ok 的——这类事故真实存在。

第三层:内容抽样。 随机抽几条最新记录,确认数据是「新的」而不是三个月前的。

第三层最容易被跳过,也最能发现问题。上面那个反例,如果当时抽一条昨天的记录,立刻就暴露了。

恢复演练怎么做

不是「读一遍备份文件」,是真的恢复到一个独立环境并启动服务。

流程:

  1. 准备一台干净机器或容器(不能在生产机上做);
  2. 用备份文件恢复数据库和上传目录;
  3. 配置环境变量、启动服务;
  4. 访问 /healthz、打开首页、登录后台、看一篇文章;
  5. 记录整个过程的耗时(这就是真实的 RTO)。

频率:核心业务每季度一次,普通站点每半年一次。演练记录要归档,否则下次出事后没人知道上次是怎么恢复的。

异地与隔离

同一个磁盘上的备份,遇到磁盘故障一起没了。同一个机房的两份,遇到机房级故障一起没了。

最低要求:至少一份在物理隔离的位置。对象存储、另一台机器、或者定期下载到本地。

但要注意:如果备份里有数据库,它包含用户密码哈希和业务配置,上传到公开可访问的存储就是数据泄露。用私有 bucket + 加密。

保留策略

不是越多越好。常见策略:

  • 最近 7 天:每天一份;
  • 最近 4 周:每周一份;
  • 最近 12 个月:每月一份。

用「祖父-父亲-儿子」的轮转规则,能在有限空间里覆盖较长的历史。全部保留的结果通常是磁盘满了,然后有人手动删掉一批——包括最重要的那份。

一个最小可用的检查清单

  1. 备份是自动的,不依赖人记得;
  2. 用的是数据库自带的备份机制,不是 cp;
  3. 每次备份后自动跑完整性校验;
  4. 至少一份在异地;
  5. 有恢复脚本,且演练过;
  6. RPO/RTO 有明确数字,业务方认可;
  7. 备份文件的访问权限受控,且加密。

七条都做到,才算「有备份」。只做第 1 条,那叫「有文件」。

收尾

备份的本质不是保存数据,是保证能回到某个已知状态。

所以衡量标准只有一个:上次真恢复是什么时候,花了多久,数据对不对。 答不上来,就还没有备份。

备份的「最后一公里」

备份文件放在服务器上,和数据库在同一块盘,等于没做异地。但把备份传到对象存储又会遇到两个具体问题。

一是凭据。上传需要密钥,密钥放在服务器上,服务器被攻破时备份也一起被删。更稳的做法是让备份机主动来拉取,服务器只提供只读访问。

二是加密。备份里有密码哈希和业务配置,明文上传等于把数据库公开。用 age 或 gpg 做对称加密,密钥单独保管——不要和备份放在一起。

备份也要能被删除

保留策略里最容易忽略的是「怎么安全地删」。

旧备份里同样有用户数据,一直留着意味着风险敞口一直在。按周期自动清理,比「先都留着」更负责任。

你认为这篇文章怎么样?

还没有表情反馈

分享文章