第 8 章 · 故障恢复

崩了之后怎么救回数据:核心是日志——先写日志、后写数据(WAL),再靠 undo/redo 双向修复。

8.1 三类故障

故障影响范围数据是否损坏恢复手段
事务故障单个事务(逻辑错/死锁被回滚)否,内存/未提交undo 回滚
系统故障整个系统(掉电/崩溃)内存丢失,磁盘数据在redo + undo
介质故障磁盘损坏是,数据真没了备份 + redo 日志重放

关键:前两类磁盘数据没丢,只需「已提交的重做、未提交的撤销」;介质故障得靠备份副本 + 日志。

8.2 日志:redo 与 undo

  • redo 日志:记「改成了什么」(新值),用于重放已提交但未落盘的修改,保持久性。
  • undo 日志:记「原来是什么」(旧值),用于回滚未提交的修改,保原子性。
事务 T:A = A - 100
redo 日志:<T, A, 新值>    → 崩溃后重做,把 A 写成新值
undo 日志:<T, A, 旧值>    → 回滚时撤销,把 A 写回旧值

对比:redo vs undo——redo 面向已提交,向前推到提交后状态,解决持久性;undo 面向未提交,向后拉回事务前状态,解决原子性。一次系统故障恢复 = 先 redo 已提交,再 undo 未提交。

8.3 WAL:先写日志再写数据

WAL(预写式日志) 是恢复正确性的根基,规则一条:

任何数据页落盘之前,它对应的日志必须先落盘(先写日志,后写数据)

若数据页落盘后、日志还没写就崩溃,已提交修改无法重做,持久性被破坏。WAL 保证日志先于数据,崩溃后总能从日志重建正确状态;且把随机写(数据页)转成顺序追加写(日志),反而更快。

8.4 检查点(Checkpoint)

恢复若每次从头扫日志代价不可接受。检查点定期做三件事:

  1. 把缓冲池脏页刷盘;
  2. 日志写一条 <CHECKPOINT> 记录(含当时活跃事务清单);
  3. 恢复只需从最近检查点开始。
时间轴: ... 检查点C1 ... 检查点C2 ... ─崩溃─▶ 恢复
恢复只需处理 C2 之后的事务,C2 之前已落盘

检查点越频繁恢复越快,但正常运行刷盘开销越大。

8.5 恢复策略总览

  • 事务故障:undo 日志,把该事务改过的值逐个写回旧值(逆序)。
  • 系统故障:① redo——从最近检查点起重放已提交事务的日志;② undo——未提交事务逆序撤销。
  • 介质故障:装载最近完整备份(冷备/热备),再用 redo 日志重放备份后的已提交修改,补到崩溃点。

对比:三种故障恢复——事务故障最轻,仅内存层 undo;系统故障磁盘完好,用 redo + undo 拉到一致,扫最近检查点后日志;介质故障最重,须备份 + 重放日志,备份间隔决定数据丢失窗口(RPO)。共同点:都靠日志——日志是恢复的唯一真相来源。