36.2 备份策略 (全量 / 增量 / 差异)
一句话
全量、增量、差异不是三种“备份技术”,而是三种成本结构:全量用空间换恢复简单,增量用空间换恢复链长,差异取中间;选哪个由 RTO(恢复要多久) 决定,而不是由“能省多少存储”决定。
三种策略的定义只差一句话
| 策略 | 每次备份什么 | 恢复要哪些文件 | 备份量随时间 |
|---|---|---|---|
| 全量 | 全部数据 | 最新那一份 | 恒定,等于数据量 |
| 增量 | 上次备份(任意类型)之后的变化 | 全量 + 期间所有增量,按顺序 | 最小 |
| 差异 | 上次全量之后的累计变化 | 全量 + 最新一份差异 | 逐日变大,下次全量后归零 |
三者的差别不在“备份怎么写”,而在恢复时要串多少个文件。这一点决定了 RTO,也决定了恢复失败的概率——每多一个文件,就多一次校验、多一个可能损坏的环节。
算一笔账:30 天、1 TiB、日变更 5%
设定:数据 1024 GiB,每天变更 5%,即约 51.2 GiB,备份与恢复吞吐都按 200 MB/s 算。
| 策略 | 备份文件数 | 总占用 | 单次最大 | 恢复文件数 | 恢复耗时 | RPO |
|---|---|---|---|---|---|---|
| 每天全量 | 30 | 30.00 TiB | 1024 GiB | 1 | 87.4 min | 24h |
| 周全量 + 日增量 | 30 | 6.25 TiB | 1024 GiB | 7 | 113.6 min | 24h |
| 周全量 + 日差异 | 30 | 9.25 TiB | 1024 GiB | 2 | 113.6 min | 24h |
| 周全量 + 6h 增量 | 105 | 6.25 TiB | 1024 GiB | 25 | 113.6 min | 6h |
四个反直觉结论:
- 每天全量的恢复最快(87.4 分钟、1 个文件),尽管它最贵(30 TiB)。空间和 RTO 是直接交换的。
- 增量和差异的恢复耗时完全一样(113.6 分钟)。因为两者都要重放“一整周的变化”,只是增量分成 7 份、差异合成 1 份。差异多花的 3 TiB 买的不是速度,是文件数从 7 降到 2。
- 6h 增量把 RPO 从 24h 压到 6h,存储一分没多花,代价是文件数从 30 涨到 105、恢复链从 7 个涨到 25 个。
- RPO 与恢复复杂度是同一枚硬币的两面。想缩小 RPO,就得提高备份频率,而频率一高,链就变长。
🔑 备份策略的正确顺序:先定 RTO/RPO(见 36.1 RTO / RPO),再选策略。先选“增量省空间”,再发现恢复要 4 小时,是这类系统最常见的返工原因。
恢复链:增量最脆弱的地方
周全量 + 日增量,最坏恢复路径:
full-2026-10-18 → inc-19 → inc-20 → inc-21 → inc-22 → inc-23 → inc-24
↑ ↑
任一文件损坏,后面全部作废;且必须按顺序重放
| 风险 | 增量 | 差异 | 全量 |
|---|---|---|---|
| 单文件损坏的影响 | 该文件之后的时间点全部不可恢复 | 只丢这一天的差异 | 只丢这一份 |
| 恢复脚本复杂度 | 高(循环 + 顺序 + 链校验) | 低(固定两步) | 最低 |
| 恢复时的 IO 模式 | 大量随机读 + 顺序重放 | 同左,但文件少 | 顺序读 |
| 演练难度 | 高(要造出“第 6 天故障”) | 中 | 低 |
三种缓解手段:
- 合成全量(synthetic full):备份软件在后台把“全量 + 增量”合并成一份新的全量,不重新读源数据。链长被定期截断,恢复又回到 1 个文件。
- 定期全量 + 保留多代:每周全量保留 4 代,最坏恢复链不超过 6。
- 校验与隔离:每份备份写完做 checksum 并抽样恢复;损坏的备份要能被发现,而不是在恢复时才发现。
快照不是备份
这是灾备里最贵的一类误解:
| 手段 | 保护什么 | 不保护什么 |
|---|---|---|
| 存储快照 | 误删、逻辑错误(秒级回滚) | 存储阵列故障、机房故障、勒索软件加密、误删快照本身 |
| 备份 | 介质/机房/逻辑错误 | 业务连续性(恢复慢) |
| 副本(主从) | 单机故障 | 逻辑错误(删库会同步到从库) |
| 归档 | 长期留存与合规 | 快速恢复(取回要分钟到小时) |
快照与源数据在同一个故障域,共享同一套权限:拿到管理员账号的人可以先把快照删了再删库。备份必须离开源系统——不同账号、不同存储、最好不同机房,关键数据再加一份离线/不可变(WORM)副本。
⚠️ “3-2-1” 说的是 3 份副本、2 种介质、1 份异地;面对勒索软件还要加两条:1 份离线或不可变、0 错误(恢复演练验证过)。只做 3-2-1 不做验证,等于买了保险没看过条款。
一致性:备份出来的数据能不能直接用
| 方式 | 怎么备 | 一致性 | 恢复 |
|---|---|---|---|
| 物理备份 | 拷贝数据文件 + 重放 WAL/binlog | 崩溃一致(恢复到某个 LSN) | 快,适合大库 |
| 逻辑备份 | mysqldump / pg_dump 导出 SQL | 事务一致(某一时刻快照) | 慢(要重新建索引) |
| 存储快照 | 卷级快照 | 取决于是否冻结写入 / 是否多卷原子 | 最快,但多卷可能不一致 |
| 文件拷贝 | cp / rsync 运行中的数据目录 | 不一致,恢复后大概率起不来 | 不可用 |
关键区分:崩溃一致性(像拔电源后重启,数据库自己能恢复)vs 事务一致性(所有表处于同一逻辑时刻)。跨多个存储(数据库 + 对象存储 + 搜索索引)时,单库备份无法保证整体一致,需要业务级的“一致性点”(如停写窗口、双写日志、按事务 ID 对齐)。
可运行的成本模型
下面这段代码把上面那张表算出来,顺便回答“多花 3 TiB 的差异备份买到了什么”。
package main
import "fmt"
const (
dbGiB = 1024.0 // 全量数据量
dailyRate = 0.05 // 每天变更 5%
mbs = 200.0 // 备份与恢复吞吐同为 200 MB/s
days = 30
)
func change() float64 { return dbGiB * dailyRate } // 51.2 GiB
// 把 GiB 换算成「吞吐 200MB/s 下需要多少分钟」
func mins(gib float64) float64 { return gib * 1024 / mbs / 60 }
type plan struct {
name string
files int
totalGiB float64
maxJobGiB float64
restoreN int
restoreGiB float64
rpoHours float64
}
func main() {
full := dbGiB
inc := change()
fmt.Printf("数据 %.0f GiB,日变更 %.0f%%,吞吐 %.0f MB/s,周期 %d 天\n", dbGiB, dailyRate*100, mbs, days)
// ① 每天全量:最简单,最贵
dailyFull := plan{"每天全量", days, float64(days) * full, full, 1, full, 24}
// ② 每周全量 + 每天增量(只备份「上次备份后的变化」)
fullsB := days/7 + 1 // 第 0、7、14、21、28 天
incB := days - fullsB
// 最坏情况:全量后第 6 天故障,要恢复全量 + 6 个增量
restoreB := full + 6*inc
weeklyInc := plan{"周全量+日增量", fullsB + incB, float64(fullsB)*full + float64(incB)*inc,
full, 1 + 6, restoreB, 24}
// ③ 每周全量 + 每天差异(备份「上次全量后的累计变化」,逐日变大)
fullsC := days/7 + 1
var diffC float64
for d := 0; d < days; d++ {
if d%7 != 0 {
diffC += inc * float64(d%7) // 第 1 天 1×inc,第 6 天 6×inc
}
}
restoreC := full + 6*inc // 恢复全量 + 当天最新的那份差异
weeklyDiff := plan{"周全量+日差异", fullsC + (days - fullsC),
float64(fullsC)*full + diffC, full, 2, restoreC, 24}
// ④ 每周全量 + 每 6 小时增量:RPO 从 24h 降到 6h,恢复链变长 4 倍
incD := days*4 - fullsB*4
restoreD := full + 24*(inc/4) // 全量后最多 24 份 6 小时增量
sixHour := plan{"周全量+6h增量", fullsB + incD, float64(fullsB)*full + float64(incD)*(inc/4),
full, 1 + 24, restoreD, 6}
fmt.Printf("\n%-16s %6s %10s %10s %8s %9s %6s\n",
"策略", "文件数", "总占用TiB", "单次最大", "恢复文件", "恢复耗时", "RPO")
for _, p := range []plan{dailyFull, weeklyInc, weeklyDiff, sixHour} {
fmt.Printf("%-16s %8d %10.2f %10.0f %8d %7.1fmin %5.0fh\n",
p.name, p.files, p.totalGiB/1024, p.maxJobGiB, p.restoreN, mins(p.restoreGiB), p.rpoHours)
}
// 增量链断一环的后果
fmt.Printf("\n增量链最坏恢复:%d 个文件、共 %.0f GiB、%.1f 分钟;其中任意一个文件损坏,整条链作废\n",
weeklyInc.restoreN, weeklyInc.restoreGiB, mins(weeklyInc.restoreGiB))
fmt.Printf("差异备份最坏恢复:%d 个文件、共 %.0f GiB、%.1f 分钟;只依赖「全量 + 1 份差异」\n",
weeklyDiff.restoreN, weeklyDiff.restoreGiB, mins(weeklyDiff.restoreGiB))
}
输出:
数据 1024 GiB,日变更 5%,吞吐 200 MB/s,周期 30 天
策略 文件数 总占用TiB 单次最大 恢复文件 恢复耗时 RPO
每天全量 30 30.00 1024 1 87.4min 24h
周全量+日增量 30 6.25 1024 7 113.6min 24h
周全量+日差异 30 9.25 1024 2 113.6min 24h
周全量+6h增量 105 6.25 1024 25 113.6min 6h
增量链最坏恢复:7 个文件、共 1331 GiB、113.6 分钟;其中任意一个文件损坏,整条链作废
差异备份最坏恢复:2 个文件、共 1331 GiB、113.6 分钟;只依赖「全量 + 1 份差异」
参数怎么给
| 你的情况 | 策略 | 关键点 |
|---|---|---|
| 数据 < 1 TiB、RTO < 2h | 每天全量 | 空间换简单,恢复只依赖 1 个文件 |
| 数据 1–50 TiB、RTO < 4h | 周全量 + 日增量 + 周中合成全量 | 链长 ≤ 6 |
| 数据 > 50 TiB、备份窗口不够 | 增量 + 合成全量 + 永久增量 | 首次全量后不再重读源 |
| 合规要求保留 7 年 | 全量 + 归档层 + 不可变副本 | 见 39.3 存储分级 |
| 数据库 | 物理备份 + WAL 持续归档 | 逻辑备份只做小库/跨版本迁移 |
反模式
| 反模式 | 后果 |
|---|---|
| 用快照当备份 | 存储故障、勒索软件、误删快照时一起丢 |
| 只做增量、从不合成全量 | 恢复链越拖越长,某天发现链断了 |
| 备份和源数据用同一套账号/同一个机房 | 一次入侵或一次机房故障全丢 |
| 备份不加密、或密钥与备份放一起 | 备份泄露 = 数据泄露;密钥丢失 = 备份作废 |
| 备份有监控、恢复没演练 | RTO 只是纸面数字,真故障时 3 倍超时 |
| 备份窗口压在业务高峰 | 备份抢 IO,白天延迟上升,然后“优化”成不备份 |
| 只验证备份任务成功,不验证内容 | 备份成功 ≠ 可恢复,损坏的备份比没有更危险 |
| 保留策略无限增长 | 存储成本线性上涨,且没人敢删 |
| 跨库/跨存储不做一致性点 | 恢复后数据对不上,业务自己修 |
自检
Q1 30 天、1 TiB、日变更 5%:每天全量占 30 TiB、恢复 87.4 分钟;周全量+日增量只占 6.25 TiB,恢复却要 113.6 分钟。为什么“更省空间”反而“更慢恢复”?
▸ 答案:全量的每份备份都是自包含的,恢复只需读 1 个 1 TiB 文件;增量备份只存变化,恢复必须“全量 + 一周内所有增量”按顺序重放,总字节数从 1 TiB 涨到 1.3 TiB,还要多 6 次打开文件、校验、定位的固定开销。空间省下来的是“重复数据”,时间花出去的是“重放链”。所以 RTO 紧的系统宁可多花存储做全量,或者用合成全量把链截断。
Q2 增量链里第 3 个文件损坏,为什么第 4、5、6 个文件都“没用”了?有哪些工程手段能避免?
▸ 答案:增量只存“相对于上一状态的差异”,第 4 份增量的内容依赖第 3 份应用后的状态;缺了第 3 份,后续补丁没有正确的基线,无法重放。手段:① 合成全量——后台把全量+增量合并成新的全量,链被定期截断;② 每次全量保留多代,把最坏链长限制在一周内;③ 每份备份写 checksum 并抽样恢复;④ 关键库用 WAL/binlog 持续归档,恢复点由日志序列决定,而不是由“文件链”决定。
Q3 差异备份比增量多占 48% 空间(9.25 vs 6.25 TiB),恢复耗时却完全一样(113.6 分钟)。那这 48% 买到了什么?
▸ 答案:买到恢复路径的简单性与可靠性:文件数从 7 降到 2,意味着只需校验 2 个对象、按固定两步恢复;增量要按顺序重放 7 个文件,任何一个损坏都让整条链作废,恢复脚本和演练复杂度都更高。它买到的是“更低的恢复失败概率”和“更短的排障时间”,不是更快的字节吞吐。若团队没有能力维护链式恢复,差异备份的溢价是值的。
Q4 你们每小时对云盘做一次快照,保留 7 天,机房断电后却恢复不了。为什么?快照到底防什么?
▸ 答案:快照与源盘在同一个存储系统、同一个可用区,断电/阵列故障时快照一起不可用;如果账号被盗,攻击者可以先删快照再删数据。快照防的是逻辑错误(误删、错误发布、批量改坏),恢复速度快(秒级到分钟级),但它不是备份。机房级故障要靠跨地域复制的备份或副本;勒索软件要靠离线/不可变副本。判断标准:快照能不能在“源系统整体消失”后独立恢复?不能就不是备份。
Q5 把 RPO 从 24h 压到 6h,存储没多花,代价是什么?什么时候这个代价不可接受?
▸ 答案:代价是备份次数 ×4、恢复链 ×4(文件数 30 → 105,恢复文件 7 → 25)以及备份系统的调度/校验负担;每次备份都要占 IO 与窗口,链越长,恢复越慢、越容易断。不可接受的情况:① 团队没有自动化的链校验与合成全量;② 恢复窗口本身就紧(RTO < 2h),25 个文件的重放会把 RTO 吃掉;③ 备份窗口已经和业务高峰重叠。此时应先上合成全量或 WAL 持续归档,而不是继续加密备份频率。
跨篇相关:RTO/RPO 的定义与换算见 36.1 RTO / RPO;恢复到另一套环境需要预置到什么程度,见 36.3 冷备 / 温备 / 热备;跨机房保留副本属于灾备拓扑问题,见 36.4 两地三中心与多活;备份数据的长期留存通常落在归档层,见 39.3 存储分级。