🏺 第16章 Oracle 数据备份与恢复
📄 一句话概括

备份策略不是「多久备一次」这么简单,它是两个问题:能丢多少(RPO)、多久能恢复(RTO)。 前者决定备份频率,后者决定用全备还是增量。 增量备份分三种:0 级等于全备但能接链、1 级差异备「自上次任意级别」、 1 级累积备「自上次 0 级」。 差异备得少、恢复链长;累积备得多、恢复链短。

📝 本章和前面几章的关系

16.2 讲的是部件和通道。这一篇讲怎么用它们干活:备什么、备多勤、怎么备增量。 读完这一篇要能回答一个问题:给定「最多丢一小时、四小时内必须恢复」的要求, 备份计划该怎么定。

一、备份策略:先定能丢多少,再定多久备一次

两个指标定一切:RPO 是「最多能接受丢多久的数据」,RTO 是「故障后多久必须恢复」。 RPO 决定备份频率——要求最多丢一小时,那至少每小时要有一次能恢复到「一小时前」的东西。 RTO 决定备份形式——要求四小时恢复,就不能用一条要应用二十个增量的链。 这两个数只能由业务给,不能由 DBA 猜。「每天凌晨全备」这句话背后其实是一个假设: 最多丢 24 小时可以接受。这个假设对不对,得业务点头。 保留策略有两种写法,二选一:REDUNDANCY 2 是「留两份」,简单但不看时间; RECOVERY WINDOW OF 7 DAYS 是「能恢复到七天内任意点」,更贴合「能丢多少」这个说法。 推荐后者,因为它直接对应 RPO。而且它算的是「满足这个窗口最少要留哪些备份」, 会自动帮你算冗余——代价是每天的备份该留几个不固定,看着不如「留两份」直观。 REPORT OBSOLETE 列出「按策略可以删的」,DELETE OBSOLETE 真删。 注意「过期」和「失效」是两个词:OBSOLETE 是策略上不需要了,EXPIRED 是文件已经不在了。 前者可以放心删,后者只是元数据要清理。

二、备份数据库文件与归档日志

最常用的五条命令,级别从大到小:

命令 备什么
BACKUP DATABASE 全部数据文件加控制文件
BACKUP TABLESPACE users 一个表空间的数据文件
BACKUP DATAFILE 4 一个数据文件
BACKUP ARCHIVELOG ALL 全部归档日志
BACKUP CURRENT CONTROLFILE 当前控制文件

生产上很少单独用 BACKUP DATABASE,更常见的是 BACKUP DATABASE PLUS ARCHIVELOG。 这个写法会自动按固定顺序做五件事,顺序本身就是它的价值。 ① 先切一次日志——ALTER SYSTEM ARCHIVE LOG CURRENT。 ② 备份所有归档日志。 ③ 备份数据文件。 ④ 再切一次日志。 ⑤ 备份这期间新产生的归档。 为什么两头都要切?第一次切是为了「把备份开始前的日志全部收进来」, 第二次切是为了「把备份过程中产生的日志也收进来」。 少了第二次,备份出来的数据文件就缺了「备份期间那一段」的重做—— 恢复时会报「找不到需要的归档日志」。 这条坑很隐蔽:备份成功了,LIST BACKUP 看着也正常,只有真恢复的时候才发现缺日志。 所以「备份成功」和「备份可用」是两件事——这一篇最后一段讲怎么验证。

三、增量备份:三级三义

先纠正一个常见误解:0 级增量不等于「什么都不备」,它就是一次全备。 区别在于它「登记进了增量链」——只有 0 级备份才能当增量链的起点,普通的全备不行。

级别 备什么 命令
0 级 全部块,并且成为增量链起点 INCREMENTAL LEVEL 0
1 级差异 自上次 1 级或 0 级以来变的块 INCREMENTAL LEVEL 1
1 级累积 自上次 0 级以来变的块 LEVEL 1 CUMULATIVE

「差异增量」是默认行为,不加 CUMULATIVE 就是它。 所以写 BACKUP INCREMENTAL LEVEL 1 DATABASE 得到的是差异增量,要累积必须显式写上那个词。 这一点很容易记反:名字里带「累积」的才是备得多的那个。 两者的取舍可以用一句话概括:差异增量省备份空间、费恢复时间;累积增量费备份空间、省恢复时间。 因为差异增量恢复时要「0 级加中间每一个 1 级」按顺序应用,累积增量只要「0 级加最近一个累积」。 还有一个实务细节:增量备份默认会「扫全表比对 SCN」来判断哪些块变过。 这意味着 1 级增量并不像想象中那么快——它省的是「写」,不是「读」。要连读都省,得开块变更跟踪。

四、块变更跟踪:让增量不用扫全表

原理很朴素:用一个位图文件记「哪些块改过」,改块的时候顺手打个标记。增量备份时直接读位图, 不用扫全表比对。 开启命令是 ALTER DATABASE ENABLE BLOCK CHANGE TRACKING,后面跟 USING FILE 加路径。 关掉是 DISABLE BLOCK CHANGE TRACKING,查状态看 V$BLOCK_CHANGE_TRACKING。 它的收益随库变大而变大:小库扫一遍也就几秒,大库扫一遍要几十分钟。 所以「要不要开」的答案取决于库多大、增量多久跑一次。 代价有两个:多一个文件要维护(它也会坏),以及每次改块多一次写位图的开销。 后一个开销很小但真实存在——高频写入的表上能测出来。所以「开了只有好处」是不对的, 只是好处通常大于代价。

五、备份的校验:备份成功不等于备份可用

三种验证,力度递增。 ① VALIDATE DATABASE——检查数据文件有没有坏块,不产生备份。 ② BACKUP VALIDATE DATABASE——边验证边备份,坏块会记进 V$DATABASE_BLOCK_CORRUPTION。 ③ RESTORE DATABASE VALIDATE——真去读备份文件,验证「这份备份能不能恢复」。 第 ③ 种最接近真实:它把备份文件读一遍、解压、校验块,但不写回数据文件。 所以它能在不影响生产的情况下回答「这份备份到底能不能用」。 为什么必须做这一步:备份文件也可能坏。磁盘坏道、传输截断、压缩算法出错,都会产生「看着有、 其实读不出来」的备份。而这种事通常只在真出事那天才发现——那时候已经来不及了。 所以一条实务建议:每周至少跑一次 RESTORE ... VALIDATE, 并且定期做「真恢复到另一台机器」的演练。前者验证文件, 后者验证流程——很多恢复失败不是文件坏了,是步骤漏了。

六、动手 Demo:三种增量策略的账:每轮备多少块、恢复要几个片

这一篇的 Demo 用 8 个「数据文件」、每个 5000 块来算三种策略的账。每轮随机改 200 块,跑五轮, 统计每轮各策略要备多少块。 然后算第二个账:恢复时要按顺序应用几个备份片。这一列最容易被忽略,但它直接决定 RTO。

# 三种增量策略各备多少块:8 个文件 × 5000 块,每轮改 200 块
import random
NF, NB = 8, 5000
rnd = random.Random(7)
stamp = [[0] * NB for _ in range(NF)]  # 每块最后被改的「时刻」
level0, clock = 1, 1                  # 0 级备份的时刻
tot = [0, 0, 0]
for r in range(1, 6):
    clock += 1
    ch = set()
    while len(ch) < 200:
        ch.add((rnd.randrange(NF), rnd.randrange(NB)))
    for fi, bi in ch:
        stamp[fi][bi] = clock
    full = NF * NB
    diff = sum(1 for fi in range(NF) for bi in range(NB)
               if stamp[fi][bi] > clock - 1)     # 上次备份之后
    cum = sum(1 for fi in range(NF) for bi in range(NB)
              if stamp[fi][bi] > level0)         # 上次 0 级之后
    print("第 %d 轮:全备 %d 块,差异 %d 块,累积 %d 块"
          % (r, full, diff, cum))
    tot = [tot[0] + full, tot[1] + diff, tot[2] + cum]
print("五轮合计:全备 %d,差异 %d,累积 %d" % tuple(tot))

实跑输出:

--------------------------------------------------------------------
第七十二课:全备、差异增量、累积增量——三种策略的账
--------------------------------------------------------------------

  **增量备份的前提是「知道哪些块变过」。**
  **Oracle 靠数据块里的 SCN 比对,或者开块变更跟踪(BCT)记一份位图。**
  **这一课用 8 个「数据文件」、每个 5000 块来算三种策略的账。**

  **初始状态:8 个文件 × 5000 块 = 40000 块,全部是脏的(都要备)。**

  轮次 改动块 全备  差异增量 累积增量
  -----------------------------------
  1    200    40000 200      200
  2    200    40000 200      399
  3    200    40000 200      599
  4    200    40000 200      798
  5    200    40000 200      998
  已选择 5 行

  **五轮 0 级之后一共备了多少块:**

  策略            累计备份块 恢复要几个备份片
  --------------------------------------------------------
  每轮全备        200000     1 个(最近那次)
  0 级 + 差异增量 1000       1 + 本轮数(0 级加每轮 1 级)
  0 级 + 累积增量 2994       2 个(0 级 + 最近一个 1 级)
  已选择 3 行
  **三行数字就是全部取舍:**
  **全备每次最贵、恢复最简单;差异增量每次最便宜、恢复最麻烦;累积增量在中间。**
  **「恢复要几个备份片」这一列最容易被忽略,但它决定恢复要多久。**
  **差异增量恢复时要按顺序应用一串增量,中间任何一个坏了,整条链就断了。**
  **所以常见的实际策略是:每周一次 0 级全备,每天一次差异增量,遇到大变更再补一次累积增量。**
  **这不是最优解,是把「备份窗口」和「恢复时间」两笔账折中。**

  备份链越长,中间断一环的概率越大
  --------------------------------------------------------------------

  策略            链上备份片 整条链全好
  -------------------------------------
  每轮全备        1          0.9990
  0 级 + 累积增量 2          0.9980
  0 级 + 差异增量 6          0.9940
  已选择 3 行
  **这张表的算法:假设每个备份片完好的概率是 0.999,链上 n 个就乘 n 次。**
  **注意 0.999 是个【假设】,不是实测值**——真实磁盘的损坏率比这高得多。
  **所以看这张表别看绝对值,看趋势:链越长,全好的概率越低。**
  **而一旦中间某一环坏了,只能恢复到它前面那一个备份点**——**这就是差异增量省空间的隐性代价。**

第一张表:全备每轮恒定 4 万块,差异增量每轮恒定 200 块,累积增量从 200 涨到 998。 三行数字把三种策略的性格写清楚了。 注意累积增量那列不是「200 乘轮数」,而是 200、399、599、798、998。 因为每轮改的 200 块是随机的,跟前面几轮有重叠——重叠的块只算一次。这也是真实情况:改得越集中, 累积增量涨得越慢。 第二张表:五轮累计,全备 20 万块、差异 1000 块、累积 2994 块。差异增量只有全备的 0.5%—— 这就是它省空间的程度。 但第三列「恢复要几个备份片」把账翻回来了:差异增量要 1 加 5 等于 6 个,累积只要 2 个。 恢复时每多一个片,就多一次读取、多一次应用,也多一个「坏了就断链」的风险。 最后那张可靠性表要看清前提:0.999 是假设的「单个备份片完好概率」,不是实测值。 真实磁盘的损坏率比这高,而且还有人为误删。 所以那张表别看绝对值,看趋势:链越长,全好的概率越低。 把两张表合起来看,就能明白为什么实际策略通常是「周全备加日差异加补累积」:平时用差异省窗口, 关键时刻用累积把链缩短。这不是理论最优,是把两笔账折中。

30 秒实验

  1. 把每轮改动的块数从 200 改成 2000,再跑一次。 看累积增量涨得快多少、差异增量是不是还是恒定 2000——改动越密集,两者差距越小。
  2. 把改动的块固定在同一个文件的前 200 块(每轮都改同一批)。 看累积增量还会不会涨——完全不涨,因为「自上次 0 级以来」的集合没变大。
  3. 如果有 Oracle 环境, 跑 BACKUP INCREMENTAL LEVEL 1 DATABASE 之后查 V$BACKUP_DATAFILE 的 BLOCKS 列。 看它比全备少了多少。

常见误区

  1. 「0 级增量就是不做备份」。 0 级就是全备,只是它登记进了增量链。 没有 0 级,1 级增量无从谈起。
  2. 「差异增量比累积增量好」。 差异省空间、累积省恢复时间。 选哪个取决于你的 RTO,不是取决于哪个更先进。
  3. 「BACKUP DATABASE 就够了,归档不用单独备」。没有归档, 这份备份只能恢复到备份点——热备的意义就没了。
  4. 「备份成功就是备份可用」。 备份文件本身可能坏。 要跑 RESTORE ... VALIDATE,最好再做一次真恢复演练。
自测三问(点开对答案) 1. RPO 和 RTO 分别决定什么? —— **RPO 是「最多能丢多久的数据」,决定备份频率;** **RTO 是「多久必须恢复」,决定用全备还是增量。** 2. `BACKUP DATABASE PLUS ARCHIVELOG` 为什么要切两次日志? —— **第一次切把「备份开始前」的日志全收进来,第二次切把「备份期间」产生的日志收进来。** 少了第二次,恢复时会缺那一段的重做。 3. 1 级差异增量和 1 级累积增量的区别是什么? —— **差异增量备「自上次 1 级或 0 级以来」变的块,累积备「自上次 0 级以来」变的块。**前者小、 恢复链长;后者大、恢复链短。 4. 备份做完之后,用什么命令验证「这份备份能不能恢复」? —— **`RESTORE DATABASE VALIDATE`。** 它真去读备份文件、解压、校验块,但不写回数据文件, 所以不影响生产。

下一篇讲完全恢复。 备份做得再好,恢复不起来等于零。下一篇用两个模式各演一遍: NOARCHIVELOG 丢一半,ARCHIVELOG 一行不丢。

相关笔记