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,预写日志)要求:
- 某数据页写回磁盘前,与该修改有关的日志必须先进入稳定存储。
- 事务报告提交成功前,保证提交所需的日志记录必须已持久化。
因此即使修改后的数据页尚未落盘,系统也能在重启后依据日志重做;若事务未提交,则可依据 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 可能已经无法恢复,基本步骤是:
- 更换或修复故障介质。
- 装入最近一次可靠的完全备份,把数据库恢复到转储点 $T_c$。
- 按顺序重放 $T_c$ 之后的归档日志,把数据库前滚到目标时刻 $T_f$ 或指定时间点。
- 校验数据文件、日志序列和数据库一致性后再开放服务。
图示事务分析:
- $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 取决于重放的日志是否包含未提交更新。