跳转至

数据库恢复

约 1797 个字 预计阅读时间 6 分钟

概述

  • 故障是不可避免的,包括:硬件故障、软件错误、操作失误、恶意破坏等

  • 故障的影响主要表现为:运行事务非正常中断、影响数据的正确性、数据丢失

故障的种类

  1. 事务内部的故障

    • 事务故障主要是一些非预期的,运算溢出、死锁
  2. 系统故障

    • 称为软故障,造成系统停止运作,需要重新启动;数据库在内存里的缓存信息全部丢失
    1. 发生故障时,如果尚未完成的事务可能一部分结果已经写回数据库了,就需要UNDO所有未完成事务

    2. 发生故障时,已完成的事务结果可能部分或全部留在缓冲区尚未写回,就需要REDO

  3. 介质故障:硬故障,外存损坏

  4. 病毒

恢复技术

  • 建立数据冗余的常见方法:数据转储(backup),日志文件(logging)

转储方法

  1. 静态转储:数据库停止服务,期间不允许任何的access,然后进行转储

    • 优点:实现简单;缺点:数据库可用性低
  2. 动态转储:转储操作与用户事务并发进行,期间允许access

    • 优点:不用等待事务结束,不影响事务进行;缺点:不能保证副本的数据正确有效

    • 还要将转储期间发生的事务以logging形式记录

登记日志文件

  • 日志文件的格式:以log record为单位的日志文件,以block为单位的日志文件
  1. 以记录为单位的日志文件

    log record的内容:

    • 事务标识(txn_id)

    • 操作类型(增删改查)

    • 操作对象(记录内部标识)

    • insert_key-value, delete_key-value, old_key-value, new_key-value

  2. 以数据块为单位的日志文件

    事务标识、被更新的数据块

登记日志文件遵循两条原则

  1. 登记的次序严格按照并发事务执行的顺序

  2. 必须先写日志文件,后写数据库

恢复策略

事务故障的恢复

  • 事务故障:事务在运行至正常终点前被终止,恢复子系统利用日志文件撤销(UNDO)此事务对数据库的修改

  • 恢复步骤

  1. 反向扫描文件日志,查找该事务的更新操作

  2. 对该事务的更新操作执行逆操作

  3. 继续扫描,重复;直至读到此事务的开始标记,事务故障恢复就完成了

系统故障的恢复

  • 系统故障:1. 事务未完成就已经把数据写回数据库;2. 事务完成了但是结果还在缓冲区

  • 恢复方法:UNDO未完成的事务,REDO已完成的事务

  • 恢复步骤

  1. 正向扫描日志文件,找出故障发生前已经完成的事务,加入REDO队列;找出未完成的事务,加入UNDO队列

  2. 对撤销队列事务进行UNDO:反向扫描 + 逆操作

  3. 对重做队列事务进行REDO:正向扫描 + REDO

具有检查点的恢复技术

为什么提出checkpoint

  • 我们在利用日志技术进行恢复时,有两个问题需要优化:
  1. 搜索整个日志需要耗费大量的时间

  2. REDO需要耗费大量时间

  • 解决方法:具有检查点(checkpoint)的恢复技术,在日志文件中增加检查点记录系统中增加重新开始文件
重新开始文件

checkpoint记录的内容

  1. 活动事务列表ATL(active transaction list)

    • 记录在checkpoint开始时,所有正在进行中(已经开始但是没有提交或中止)的事务的列表;以及这些事务一个last log record的地址;
  2. 各种相关的日志序列号(lsn):last_lsn, checkpoint_lsn

  3. Dirty Page Table

分析阶段

  1. 找到最后一个检查点:recovery manager首先会找到日志中最近的checkpoint。这通常通过读取数据库控制文件或日志文件头部的一个特殊指针(有时称为“重新开始文件”或主记录中的指针)来实现,该指针指向检查点记录在日志中的位置 (LSN - 日志序列号)。

  2. 加载检查点信息:从该检查点记录中,恢复管理器加载以下信息:

    • 活动事务列表 (Active Transaction Table - ATT):记录了在检查点开始时所有正在进行的事务及其最后一条日志的 LSN。

    • 脏页表 (Dirty Page Table - DPT):记录了在检查点开始时,buffer pool中哪些数据页是脏的(已被修改但可能未写入磁盘),以及这些脏页的 recLSN(第一次使该页变脏的日志记录的 LSN)。

  3. 向前扫描日志:从找到的检查点记录的 LSN 开始,向前扫描日志文件,直到日志的末尾。

    • 更新 ATT:

      • 当遇到事务的 BEGIN 日志记录时,将该事务加入 ATT。

      • 当遇到事务的 COMMITABORT 日志记录时,将该事务从 ATT 中移除

      • 更新 ATT 中事务的 lastLSN 为其遇到的最新日志记录的 LSN。

    • 更新 DPT:

      • 当遇到数据修改的日志记录(如 UPDATE, INSERT, DELETE)时,如果被修改的页不在 DPT 中,则将其加入 DPT,并记录其 recLSN 为当前日志记录的 LSN。如果已在 DPT 中,则不需要更新 recLSN(recLSN 记录的是 首次 变脏的 LSN)。
  4. 分析阶段结束时的成果:

    • 得到一个准确的 ATT,包含了在系统崩溃时所有真正活动的事务。

    • 得到一个准确的 DPT,包含了在系统崩溃时所有可能仍在内存中且为脏状态的页,以及它们最早变脏的日志记录位置 (recLSN)。

重做阶段

  • 确保所有已提交事务的修改都已成功写入磁盘(持久性),并且将数据库恢复到崩溃发生时的确切状态
  1. 确定重做起点

    • 重做阶段的起始 LSN 通常是分析阶段确定的 DPT 中所有脏页的最小 recLSN。这意味着从这个最早可能未被持久化的修改开始重做。如果 DPT 为空(理论上,如果检查点后所有操作都落盘且没有新脏页),则可以从检查点 LSN 之后开始。
  2. 向前扫描日志并重做:从确定的重做起点 LSN 开始,再次向前扫描日志到末尾。

    对于每一条数据修改的日志记录:

    • 如果该记录影响的页 P 不在 DPT 中,则跳过此记录(因为这意味着该页在检查点时是干净的,并且之后没有再变脏,或者其修改已通过检查点或后续操作安全落盘)。

    • 如果页 P 在 DPT 中,并且该页在磁盘上的版本(通过其存储的 PageLSN 判断)比当前日志记录的 LSN 旧,并且当前日志记录的 LSN 大于等于页 P 在 DPT 中的 recLSN,则重新执行 (Redo) 该日志记录所描述的操作。

    • 重做操作后,将内存中页 P 的 PageLSN 更新为当前日志记录的 LSN。