← Back to Learning Notes

Lecture 7:数据库恢复技术

Chinese-language Computer Science 408 note: Lecture 7:数据库恢复技术. Original source available where applicable.

On this page

This note is currently available in Chinese. The original wording, formulas and diagrams are preserved to avoid an unverified technical translation.

描述:本节整理事务与 ACID、数据转储、日志与 WAL、MySQL redo/undo 日志,以及事务故障、系统故障和介质故障的恢复方法;同时完整转写检查点时序图和备份加归档日志恢复流程,并纠正课件中事务与 TCL、redo 记录范围等易混表述。

7.1 事务

7.1.1 事务的定义

事务(transaction)是用户定义的一个数据库操作序列,也是数据库的逻辑工作单位。事务中的操作形成一个不可分割的执行单元:

  • 要么全部成功并提交。
  • 要么发生错误后全部撤销,效果等同于没有执行。

典型转账事务:

START TRANSACTION;

UPDATE account
SET balance = balance - 100
WHERE account_id = 1;

UPDATE account
SET balance = balance + 100
WHERE account_id = 2;

COMMIT;

若第二条更新失败,应执行 ROLLBACK,不能只保留第一条扣款。

WARNING 课件把“事务”写成 transaction control language, TCL,二者不是同一个概念。事务是逻辑工作单位;TCL 是控制事务的 SQL 语句类别,包括 COMMIT、ROLLBACK 和 SAVEPOINT 等。

7.1.2 ACID 特性

特性 含义 主要实现机制
原子性 Atomicity 事务中的操作全部完成或全部撤销 undo 日志、回滚机制
一致性 Consistency 事务把数据库从一个满足约束的状态带到另一个满足约束的状态 正确业务逻辑、完整性约束及 A/I/D 共同保证
隔离性 Isolation 并发事务的中间状态不应相互产生不允许的干扰 锁、时间戳、MVCC、并发控制
持久性 Durability 事务一旦提交,其结果即使系统故障也不应丢失 redo 日志、WAL、稳定存储

课件机制图表达的是:undo 支撑原子性,redo 支撑持久性,并发控制支撑隔离性,三者与正确的事务逻辑共同维护一致性。

NOTE “一致状态”不是简单指数据库中只有已提交结果,而是指主外码、检查约束、业务不变量等所有规定的一致性条件均成立。

7.2 数据转储

7.2.1 基本概念

数据转储(backup)是 DBA 把数据库复制到其他可靠存储介质保存的过程,得到的副本称为后备副本或后援副本。

数据库损坏后可以重新装入后备副本,但只使用副本时,数据库只能恢复到转储完成时的状态。要恢复到更接近故障发生的时刻,还需重放此后的归档日志。

7.2.2 按运行状态分类

类型 转储期间数据库状态 特点
静态转储,冷备份 数据库停止服务,不允许事务运行 副本天然一致,实施简单,但停机时间长
动态转储,热备份 数据库继续运行并允许更新 可用性高,但必须配合日志保证副本一致性

7.2.3 按数据范围分类

类型 转储内容 特点
海量转储,完全备份 整个数据库 恢复简单,备份耗时和空间较大
增量转储 自上次备份后发生变化的数据 备份快、空间小,恢复时依赖备份链

组合后有四类:动态完全、静态完全、动态增量、静态增量转储。

7.3 日志与 WAL

7.3.1 日志的作用与内容

日志是记录事务对数据库更新操作的文件。一般应包含:

  • 事务标识。
  • 事务开始、提交或中止标记。
  • 更新对象的位置或逻辑标识。
  • 更新前值、更新后值,或足以撤销/重做更新的信息。

并发事务的日志记录必须按实际执行先后写入统一的日志序列,才能正确还原更新顺序。

7.3.2 先写日志原则

Write-Ahead Logging(WAL,预写日志)要求:

  1. 某数据页写回磁盘前,与该修改有关的日志必须先进入稳定存储。
  2. 事务报告提交成功前,保证提交所需的日志记录必须已持久化。

因此即使修改后的数据页尚未落盘,系统也能在重启后依据日志重做;若事务未提交,则可依据 undo 信息撤销。

TIP “先写日志、后写数据库”是日志恢复的关键顺序,不等于每条 SQL 后都立刻把整个数据页同步写盘。

7.3.3 二进制日志

课件中的二进制日志指 MySQL binary log(binlog)。它具有归档性质,记录对数据库产生变更的已提交事件,主要用于:

  • 基于时间点恢复。
  • 主从复制或其他复制拓扑。
  • 审计和变更追踪的辅助场景。

binlog 是 MySQL Server 层日志;InnoDB redo/undo 是存储引擎层日志,三者作用不同。

7.4 redo 日志

7.4.1 为什么需要 redo

以 InnoDB 为例,B+ 树节点存放在页中,默认数据页常为 $16\ \text{KiB}$。内存缓冲池中的页被修改后称为脏页。

若每次只修改 $1\ \text{B}$ 就随机写回整个 $16\ \text{KiB}$ 数据页,开销很大。redo 日志按顺序追加较小的变更记录,顺序 I/O 通常比大量随机数据页写入更高效。

7.4.2 作用与记录范围

redo 日志用于在故障后重放修改,支撑事务持久性:

  • 事务提交时,相关 redo 已按规则持久化,即使脏页尚未落盘也可恢复。
  • 后台线程可以稍后批量把脏页写回数据文件。
  • 崩溃恢复时,系统根据日志序列号、检查点和页状态判断需要重做的记录。

WARNING 课件写“redo 只保存事务提交但尚未写入硬盘的数据”过于绝对。redo 记录在数据页被修改时就会生成,日志缓冲中也可能含未提交事务的记录;提交决定其持久性保证,恢复算法再结合事务状态处理。

7.4.3 物理性

课件把 redo 描述为物理日志:记录表空间/页号、页内偏移及修改值等低层变更信息。更严谨地说,InnoDB redo 常称为物理或物理逻辑日志,它描述“某个数据页上发生了什么变化”,不是反向 SQL 语句。

7.5 undo 日志

7.5.1 作用

undo 日志保存足以把记录恢复到修改前版本的信息,主要用于:

  • 事务回滚,保证原子性。
  • 崩溃恢复时撤销未完成事务。
  • MVCC 为一致性读提供旧版本。

直观理解:

  • INSERT 的反向效果是删除新记录。
  • DELETE 的反向效果是恢复被删记录。
  • UPDATE 需要保存旧值或旧版本,以便恢复。

这些是帮助理解的逻辑效果,undo 记录并不等同于数据库把一条反向 SQL 文本原样保存下来。

7.5.2 产生与清理

  • DML 增删改开始时产生 undo 信息;普通 DQL 查询不直接生成用于数据修改回滚的 undo 记录。
  • insert undo 在事务提交且不再需要后可以较快释放,因为新插入版本不会被更早的快照看见。
  • update undo 涉及更新和删除形成的旧版本,提交后可能仍被其他事务的一致性读需要,不能立即删除。
  • 待旧版本不再被任何活跃读视图需要时,后台 purge 线程再回收。

7.6 故障类型与恢复

故障 影响范围 典型原因 主要恢复手段
事务故障 单个事务 运算溢出、违反约束、死锁牺牲者、程序错误 撤销该事务
系统故障,软故障 内存状态丢失,磁盘介质通常完好 断电、操作系统或 DBMS 崩溃 检查点加日志,REDO 已提交、UNDO 未提交
介质故障,硬故障 外存数据文件损坏或丢失 磁盘损坏、控制器故障、文件破坏 重装备份,再重放归档日志

7.6.1 事务故障

事务运行到正常终止点前夭折,例如:

  • 运算溢出。
  • 违反完整性约束。
  • 并发死锁中被系统选为撤销对象。
  • 程序主动回滚。

系统利用 undo 信息逆序撤销该事务已执行的更新,不影响其他已经正确提交的事务。

7.6.2 系统故障

系统故障又称软故障,造成系统停止运行并需要重启,但数据库所在外存通常没有物理损坏。

恢复目标:

  • 对故障时未提交的事务执行 UNDO。
  • 对故障前已提交、但数据页可能尚未落盘的事务执行 REDO。

7.6.3 检查点时序图完整分析

设 $T_c$ 为检查点,$T_f$ 为系统故障时刻。下面的表采用传统教材中的强制/静止检查点简化模型:检查点完成前,相关脏页已按模型要求写回,因此检查点前已提交事务可视为不需再处理。在这一模型下,五个事务按“故障时是否提交”与“提交是否早于检查点”判断:

事务 时间关系 恢复动作
$T_1$ 检查点前已提交 通常无需处理
$T_2$ 检查点前开始,检查点后、故障前提交 REDO
$T_3$ 检查点前开始,故障时仍未提交 UNDO
$T_4$ 检查点后开始,故障前提交 REDO
$T_5$ 检查点后开始,故障时仍未提交 UNDO
过去 -------- Tc(检查点) -------- Tf(系统故障)
T1: [开始---提交]                              无需处理
T2: [开始----------提交]                       REDO
T3: [开始--------------------------未提交]      UNDO
T4:               [开始------提交]              REDO
T5:                    [开始---------未提交]     UNDO

WARNING 课件文字“系统故障之后的事务直接撤销”不准确:系统故障发生后事务已经不能继续执行。应先区分故障时已提交的 winner 与未提交的 loser,再结合所采用的检查点/恢复算法决定 REDO、UNDO 范围,不能只看事务是否跨过故障时刻。

检查点的意义是缩短恢复时需要扫描的日志范围,并保存活跃事务等恢复信息;它不代表检查点前的所有数据页在所有实现中都必然完全落盘。采用 ARIES 一类模糊检查点时,T_1 的某些更新若仍在脏页中也可能需要 REDO,实际起点和范围由脏页表、recLSN、页 LSN 等恢复信息决定;ARIES 还会先“重复历史”再撤销 loser。因此上表不能脱离其简化模型直接推广。

7.6.4 介质故障

介质故障又称硬故障,指磁盘等外存损坏。仅靠当前磁盘上的 undo/redo 可能已经无法恢复,基本步骤是:

  1. 更换或修复故障介质。
  2. 装入最近一次可靠的完全备份,把数据库恢复到转储点 $T_c$。
  3. 按顺序重放 $T_c$ 之后的归档日志,把数据库前滚到目标时刻 $T_f$ 或指定时间点。
  4. 校验数据文件、日志序列和数据库一致性后再开放服务。

图示事务分析:

  • $T_1$ 在备份点前已提交,已经包含在副本中,不需再 redo。
  • $T_4$ 在备份点后开始并在介质故障前提交,需要从归档日志 redo。
  • $T_3$、$T_5$ 在故障时未提交,不应成为最终恢复结果。

若归档日志只重放已提交事件,未提交事务的更新根本不会被恢复到新磁盘,因此图中“硬盘已换,不需回滚”成立;若底层恢复过程中重放了含未提交更新的物理日志,则仍需由恢复算法撤销。不能脱离具体日志机制机械地说永远不需要 undo。

7.7 三类日志对比

日志 层次与内容 主要用途 是否直接用于事务回滚
redo log InnoDB 引擎层,页变更的物理或物理逻辑信息 崩溃恢复、持久性 否
undo log InnoDB 引擎层,旧版本或反向恢复信息 回滚、MVCC、原子性 是
binlog MySQL Server 层,已提交变更事件 复制、归档、时间点恢复 通常不用于单事务即时回滚

7.8 常考判断

7.8.1 提交后数据页尚未落盘,事务是否持久

只要 DBMS 已按持久性协议把必要 redo 记录刷入稳定存储并确认提交,之后可通过 redo 恢复,事务仍具有持久性。

7.8.2 WAL 的“先写”指什么

不是“先执行日志 SQL”,而是相关日志记录必须先于脏数据页进入稳定存储;提交所需日志还必须先于向用户报告提交成功持久化。

7.8.3 检查点后的事务是否都要 undo

错误。检查点后已经提交的事务可能需要 redo;故障时仍未提交的事务才需要 undo。

7.8.4 备份是否等于完整恢复

不等于。单独装入备份只能恢复到备份时刻;备份加归档日志才能前滚到更接近故障时刻或指定时间点。

相关知识

本节复盘

  • 事务是数据库的逻辑工作单位,TCL 是控制事务的 SQL 语句类别,二者不能混同。
  • 原子性、隔离性、持久性分别主要依靠 undo、并发控制和 redo/WAL;一致性是最终目标。
  • 数据转储分静态/动态、完全/增量四种组合,单独使用只能恢复到转储点。
  • WAL 要求日志先于数据页落盘;redo 负责重做,undo 负责回滚和旧版本,binlog 负责归档与复制。
  • 系统故障恢复时,故障前已提交但可能未落盘的事务 redo,故障时未提交的事务 undo。
  • 介质故障需要先装入备份,再用归档日志前滚;是否还需 undo 取决于重放的日志是否包含未提交更新。