恢复系统
1. 故障
1.1 故障类型
- 事务故障
- 逻辑错误:遇到非法输入、违反约束、数据溢出等内部情况而无法继续正常执行
- 系统错误:进入不良状态(死锁或内存不足),事务停滞无法执行
- 系统崩溃:由于硬件、软件或电力等问题导致系统崩溃,所有活动事务中断
- 磁盘故障:磁头损坏或存储介质损坏造成数据无法访问或者数据损坏
故障-停止假设:系统崩溃不会破坏非易失性存储中的数据
1.2 存储器类型
| 类型 | 定义 | 性质 | 例子 |
|---|---|---|---|
| 易失性存储器(volatile storage) | 在断电或系统崩溃后,数据丢失 | 容量较小,读写速度非常快,常用于存储查询结果或中间计算数据 | RAM、Cache |
| 非易失性存储器(non-volatile storage) | 在断电或系统崩溃后,数据仍然保存 | 容量较大,读写速度较慢,常用于存储表数据文件 | SSD、HDD |
| 稳定存储器(stable storage) | 在断电或系统崩溃后,数据不仅可以保存,而且即使丢失也能恢复 | 利用冗余数据存储技术,常用于存储日志文件 | RAID 阵列、云存储 |
2. 数据访问机制
驻留在磁盘上的块成为物理块,驻留在内存缓冲区中的块成为缓冲块,工作中的内存从缓冲块中读取所需要的数据进行访问,然后将读取完或更改后的数据写回缓冲块,内存缓冲区最后负责将缓冲块写回磁盘
内存缓冲区写回块原因
- 内存缓冲区不够新块进入,需要替换一些不常使用的块
- 操作系统强制将块写回
3. 基于日志的恢复
3.1 日志
日志:数据库系统中用于记录事务操作的数据结构,每个日志记录包含事务标识、操作类型、数据项标识、旧值、新值、事务类型
日志类型
- 开始记录:
<T, start> - 更新记录:
<T, X, V1, V2> - 提交记录:
<T commit> - 终止记录:
<T, abort> - 检查点记录:
<checkpoint, T1, T2, ...>
3.2 日志操作
两大核心功能
| 操作 | 撤销(UnDo) | 重做(ReDo) |
|---|---|---|
| 定义 | 回滚未提交事务的修改 | 重新执行已提交事务的修改 |
| 触发条件 | 只有事务的 Start 记录 | 存在事务的 Start 和 Commit/Abort 记录 |
| 操作 | 将数据项的值恢复为更新记录中的旧值 | 将数据项的值更新为更新记录中的新值 |
写前日志(Write-Ahead Logging, WAL):在事务提交前,必须先将日志记录写入磁盘,从而确保即使系统崩溃,也能通过日志恢复事务的修改
- 立即修改:每一次数据更新时,先写日志到磁盘,然后直接写数据到磁盘
- 延迟修改:每一次数据更新时,先写日志到磁盘,然后延迟到事务提交后再写数据磁盘
3.3 检查点
全日志扫描局限性
- 从头往后扫描日志,重做或回滚所有记录在日志中的事务,可能会非常耗时
- 对于许多已经提交且数据已写入磁盘的事务,重做这些事务是没有必要的
检查点:记录了系统中活跃事务/所有未提交事务的信息
- 系统定期触发检查点操作,往日志中添加一条记录当前所有活跃事务的状态的检查点记录
- 先将日志写入磁盘,然后将缓冲区数据块写入磁盘
- 如果发生错误,从后往前扫描日志找到最近的检查点,得到活跃事务列表
- 从最早活跃事务开始,利用恢复算法,重做所有已提交事务的更新操作,撤销所有未提交事务的更新操作
检查点除了可以减小扫描范围和重做次数,还可以用于日志清理:删除或归档在检查点之前已经提交的事务的日志记录日志记录,因为这些日志记录已经不再需要用于恢复
3.4 恢复算法
- 重做阶段:从检查点往后扫描
- 遇到更新记录:执行重做操作
- 遇到 start 记录:将事务加入 undo-list
- 遇到 abort/commit 记录:将事务从 undo-list 移除
- 撤销阶段:从后往前扫描
- 遇到更新记录且事务属于 undo-list:执行撤销操作,在末尾添加一条给该事务的撤销记录
- 遇到 start 记录且事务属于 undo-list:在末尾添加一条该事务的 abort 记录,并将事务从 undo-list 中移除
- undo-list 变为空:算法结束
4. 缓冲区管理
4.1 日志缓冲
日志记录缓冲:将日志记录先存储在主存中的缓冲区,而不是立即写入磁盘
- 日志缓冲区满:需要写入磁盘来腾出空间
- 事务提交:强制将事务相关日志记录写入磁盘
- 执行检查:强制将全部日志写入磁盘
- 定时触发:操作系统周期性地进行日志刷盘
4.2 数据库缓冲
| 策略 | 定义 | 性能 |
|---|---|---|
| Steal | 允许将未提交的块提前写回磁盘 | 缓冲区管理灵活,但恢复很复杂 |
| No-force | 事务提交时,修改的数据块不需要立即写回磁盘 | 加快事务提交,减少磁盘I/O,但空间开销大 |
| Force | 事务提交时,修改的数据块必须立即写回磁盘 | 恢复过程简单,提交事务的修改已持久化,减少数据丢失风险,但时间开销大 |
内存锁:防止提交时该块被其他事务进行修改
- 在将块写入磁盘前,获取该块的独占内存锁
- 在写入数据块之前,执行日志刷新操作,确保与该块相关的日志记录已安全存储在稳定存储中
- 将数据块写入磁盘
- 写入完成后,释放内存锁,允许其他操作访问该块
内存锁和并发控制中的锁没有关系,只要事务的写操作不在该块上,就不会阻塞事务的执行
4.3 模糊检查点
| 特性 | 普通检查点 | 模糊检查点 |
|---|---|---|
| 事务处理 | 暂停所有其他事务,直到检查点完成 | 允许事务在生成检查点的同时继续处理 |
| 脏块处理 | 一次性将所有脏块写入磁盘 | 分阶段写回脏块 |
| 日志记录 | 记录活动事务的状态 | 记录活动事务状态,并标记脏块列表 |
| 恢复过程 | 写日志,写回全部脏块 | 先写日志,再写部分脏块,最后更新 last_checkpoint 指针 |







