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

四个反直觉结论:

  1. 每天全量的恢复最快(87.4 分钟、1 个文件),尽管它最贵(30 TiB)。空间和 RTO 是直接交换的。
  2. 增量和差异的恢复耗时完全一样(113.6 分钟)。因为两者都要重放“一整周的变化”,只是增量分成 7 份、差异合成 1 份。差异多花的 3 TiB 买的不是速度,是文件数从 7 降到 2。
  3. 6h 增量把 RPO 从 24h 压到 6h,存储一分没多花,代价是文件数从 30 涨到 105、恢复链从 7 个涨到 25 个。
  4. 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 天故障”) 中 低

三种缓解手段:

  1. 合成全量(synthetic full):备份软件在后台把“全量 + 增量”合并成一份新的全量,不重新读源数据。链长被定期截断,恢复又回到 1 个文件。
  2. 定期全量 + 保留多代:每周全量保留 4 代,最坏恢复链不超过 6。
  3. 校验与隔离:每份备份写完做 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 存储分级。