1. 故障

1.1 故障类型

  • 事务故障
    • 逻辑错误:遇到非法输入、违反约束、数据溢出等内部情况而无法继续正常执行
    • 系统错误:进入不良状态(死锁或内存不足),事务停滞无法执行
  • 系统崩溃:由于硬件、软件或电力等问题导致系统崩溃,所有活动事务中断
  • 磁盘故障:磁头损坏或存储介质损坏造成数据无法访问或者数据损坏

故障-停止假设:系统崩溃不会破坏非易失性存储中的数据

1.2 存储器类型

类型定义性质例子
易失性存储器(volatile storage)在断电或系统崩溃后,数据丢失容量较小,读写速度非常快,常用于存储查询结果或中间计算数据RAM、Cache
非易失性存储器(non-volatile storage)在断电或系统崩溃后,数据仍然保存容量较大,读写速度较慢,常用于存储表数据文件SSD、HDD
稳定存储器(stable storage)在断电或系统崩溃后,数据不仅可以保存,而且即使丢失也能恢复利用冗余数据存储技术,常用于存储日志文件RAID 阵列、云存储

2. 数据访问机制

驻留在磁盘上的块成为物理块,驻留在内存缓冲区中的块成为缓冲块,工作中的内存从缓冲块中读取所需要的数据进行访问,然后将读取完或更改后的数据写回缓冲块,内存缓冲区最后负责将缓冲块写回磁盘

内存缓冲区写回块原因

  1. 内存缓冲区不够新块进入,需要替换一些不常使用的块
  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 检查点

全日志扫描局限性

  • 从头往后扫描日志,重做或回滚所有记录在日志中的事务,可能会非常耗时
  • 对于许多已经提交且数据已写入磁盘的事务,重做这些事务是没有必要的

检查点:记录了系统中活跃事务/所有未提交事务的信息

  1. 系统定期触发检查点操作,往日志中添加一条记录当前所有活跃事务的状态的检查点记录
  2. 先将日志写入磁盘,然后将缓冲区数据块写入磁盘
  3. 如果发生错误,从后往前扫描日志找到最近的检查点,得到活跃事务列表
  4. 从最早活跃事务开始,利用恢复算法,重做所有已提交事务的更新操作,撤销所有未提交事务的更新操作

检查点除了可以减小扫描范围和重做次数,还可以用于日志清理:删除或归档在检查点之前已经提交的事务的日志记录日志记录,因为这些日志记录已经不再需要用于恢复

3.4 恢复算法

  1. 重做阶段:从检查点往后扫描
    1. 遇到更新记录:执行重做操作
    2. 遇到 start 记录:将事务加入 undo-list
    3. 遇到 abort/commit 记录:将事务从 undo-list 移除
  2. 撤销阶段:从后往前扫描
    1. 遇到更新记录且事务属于 undo-list:执行撤销操作,在末尾添加一条给该事务的撤销记录
    2. 遇到 start 记录且事务属于 undo-list:在末尾添加一条该事务的 abort 记录,并将事务从 undo-list 中移除
    3. undo-list 变为空:算法结束

4. 缓冲区管理

4.1 日志缓冲

日志记录缓冲:将日志记录先存储在主存中的缓冲区,而不是立即写入磁盘

  • 日志缓冲区满:需要写入磁盘来腾出空间
  • 事务提交:强制将事务相关日志记录写入磁盘
  • 执行检查:强制将全部日志写入磁盘
  • 定时触发:操作系统周期性地进行日志刷盘

4.2 数据库缓冲

策略定义性能
Steal允许将未提交的块提前写回磁盘缓冲区管理灵活,但恢复很复杂
No-force事务提交时,修改的数据块不需要立即写回磁盘加快事务提交,减少磁盘I/O,但空间开销大
Force事务提交时,修改的数据块必须立即写回磁盘恢复过程简单,提交事务的修改已持久化,减少数据丢失风险,但时间开销大

内存锁:防止提交时该块被其他事务进行修改

  1. 在将块写入磁盘前,获取该块的独占内存锁
  2. 在写入数据块之前,执行日志刷新操作,确保与该块相关的日志记录已安全存储在稳定存储中
  3. 将数据块写入磁盘
  4. 写入完成后,释放内存锁,允许其他操作访问该块

内存锁和并发控制中的锁没有关系,只要事务的写操作不在该块上,就不会阻塞事务的执行

4.3 模糊检查点

特性普通检查点模糊检查点
事务处理暂停所有其他事务,直到检查点完成允许事务在生成检查点的同时继续处理
脏块处理一次性将所有脏块写入磁盘分阶段写回脏块
日志记录记录活动事务的状态记录活动事务状态,并标记脏块列表
恢复过程写日志,写回全部脏块先写日志,再写部分脏块,最后更新 last_checkpoint 指针