故障恢复

如何应对系统故障:

  • 提高系统的可靠性
  • 在系统故障发生后,把数据库恢复到一致状态 恢复的关键问题是如何建立冗余数据,以及利用冗余数据实施数据库恢复 恢复技术:
  • 记录日志文件
  • 数据转储

日志

日志概念

日志是用来记录事务对数据库的更新操作的文件,是日志记录的序列

  • 事务标识符:执行写操作的唯一标识符
  • 数据项标识符:事务操作对象的唯一标识符
  • 前像(BI):更新前数据的旧值;
  • 后像(AI):更新后数据的新值;

记录形式

  • <T START>:事务T开始
  • <T COMMIT>:事务T提交
  • <T ABORT>:事务T中止
  • <T,X,V1,V2>:事务T对数据项X写,前像为V1,后像为V2

日志要求

  • 每次事务执行写操作,必须在数据库修改前建立此次修改前的日志记录
  • 日志必须存储在稳定的存储器上
  • 稳定存储器中的日志记录顺序必须与写入缓冲区的日志记录顺序完全一样 一般来说,日志的记录遵循日志先写规则:在贮存中的数据块输出到数据库之前,所有可数据块中数据有关的日志记录必须已经输出到稳定存储器上 写日志的方式:
  • 后像后写
  • 后像前写
  • 后像前后写

后像后写

恢复数据库的步骤

  • 从后向前扫描数据库,将提交的事务放入队列redolist
  • 从前往后扫描日志,对遇到的每一个<T,X,V1>记录
    • 若不是队列中的事务,则无事发生
    • 若是队列中的事务,将数据项写为V1
  • 对每个未完成的事务,在日志写入一个<T,ABORT>的记录并刷新日志

后像前写

事务恢复过程:Undo,将事务T更新的所有数据项的值设为旧值; 简化日志记录内容:

  • 每一条日志记录内容为<T,X,V1>
  • 需要省去新值字段;
  • 事务T对数据项X执行写操作,写前的旧值为V1 恢复管理器执行:
  • 对日志从后往前扫描,将<T,COMMIT>记录的事务放入redo-list队列
  • 重新对日志文件从后往前扫描
  • 对每一个<T,X,V1>记录,若T在redo-list队列中,则恢复管理器忽略它;若不在,则将这个数据项改为旧值V1

后像前后写

后像在事务提交前后写入数据库,提交的时机应该和设置的缓存大小有关; 理论上事务应该按照非窃取强制写的方式刷新数据库,以保证原子性和一致性; 但是后像前后写可能存在4种组合方式刷新数据库;

  • 被修改的数据项写入磁盘的时机既可能在提交前,也可能在提交后;
  • 日志更新记录表示:<T,X,V1,V2>
  • 有些数据库实现直接构建redo-log和undo-log,而不是维护redo-list和undo-list
  • 窃取方式写日志一定包含undo操作,非强制方式写日志一定包含redo操作 执行规则:日志先写,被更新数据项写入磁盘,更新记录<T,X,V1,V2>必须已经写到稳定存储器上 恢复管理器步骤:
  • 对日志文件从前往后扫描,将有<T,COMMIT>记录和没有<T,COMMIT>记录的事务分别放入两个队列:redo-list,undo-list
  • 从前往后扫描日志,执行redo-list
  • 从后往前扫描日志,执行undo-list

等幂操作

恢复机制应该是等幂的,也就是恢复过程中再次发生崩溃,恢复机制仍然可以重新恢复,前一次恢复过程是否更新为旧值或新值无关紧要;

  • 多次执行操作与执行一次操作的效果完全相同
  • 无论redo和undo,恢复的步骤都是等幂的; 注意这时,redo-log内容属于逻辑日志,undo-log内容应该属于物理日志;

检查点

提交一致性检查点:

  • 新的事务不能开始,直到检查点完成
  • 现有事务继续执行直到中止或提交,将相关数据以及日志写入稳定存储器;
  • 将checkpoint写入稳定存储器

高速缓存一致性检查点:

  • 新的事务不能开始到检查点完成
  • 已存在的事务不允许执行新的更新操作
  • 将当前日志和数据写入磁盘
  • <checkpoint,T-list>写入稳定存储器

数据转储

数据转储是数据库恢复中采用的技术

  • 定期将整个数据库复制到其他介质保存起来
  • 备用的数据文本称为后备副本 静态转储
  • 在系统中无运行事务时进行转储
  • 转储开始时数据库处于一致性状态
  • 转储期间不允许对数据库任何存取和修改
  • 优点:实现简单
  • 缺点:降低了数据库的可用性,转储必须等待事务结束,新的事务必须等待转储结束 动态转储
  • 转储过程和事务并发进行,允许对数据库进行存取和修改
  • 优点:无需等待正在运行的事务结束,不会影响新事物的运行
  • 缺点:不能保证副本的数据正确有效
  • 利用带台转储得到的副本进行恢复,需要建立转储期间的日志活动
  • 后备副本+日志文件才能将数据库恢复到某一时刻的正确状态 完全转储: 每次转储全部数据库 增量转储: 只转储上次转储后更新过的数据
  • 从恢复角度看,使用完全转储得到的后备副本进行恢复往往更方便
  • 但如果数据库很大,事务处理又十分频繁,则增量转储方式更实用更有效

恢复策略

故障分类

事务故障

  • 逻辑错误:事务由于内部条件(如非法输入、溢出等)无法继续正常执行
  • 系统错误:系统进入一种不良状态(如死锁),事务无法继续正常执行
  • 事务故障使得事务无法达到预期的终点,数据库可能处于不一致的状态。恢复机制强行回滚该事务,撤销该事务对数据库做的任何修改 系统故障
  • 包括硬件故障、数据库软件或操作系统的漏洞造成的系统停止运转。它导致系统易失性存储器中的内容丢失,事务处理停止,但非易失性存储器中的内容不会受到破坏 介质故障
  • 在数据传送操作过程中由于磁头损坏或故障造成磁盘块上的内容丢失
  • 需使用其他非易失性存储器上的数据库后备副本进行故障的恢复

事务故障恢复

恢复技术:利用日志文件

  • 后像后写:发生故障时数据库中的数据并没有发生变化,所有数据项的修改只是在日志文件中有记录。恢复管理器忽略这些未完成的事务
  • 后像前写:发生故障时,系统可能已将部分或全部数据项的修改写入磁盘,使用日志文件撤销(UNDO)此事务对数据库的修改。
  • 后像前后写:发生故障时系统仍可能已将部分数据项的修改写入磁盘。使用日志文件撤销(UNDO)此事务对数据库的修改 一般通过日志文件,需要维护redo-list和undo-list 当系统崩溃重新启动时,它构造两个队列:undo-list存放需要撤销的事务标识符,redo-list存放需要重做得事务标识符
  • 这两个队列刚开始时都是空的
  • 队列构造步骤如下
    • 系统反向扫描日志,直到发现第一个
    • 对每一个<Ti,COMMIT>记录,将Ti加入redo-list
    • 对每一个<Ti,START>记录,如果Ti不属于redo-list,则将Ti加入undo-list

系统故障恢复

  • 利用日志文件:
  • 后像后写
  • 后像前写
  • 后像前后写

介质故障恢复

  • 装入最近的完全转储后备副本:若数据库副本是动态转储的,还需要同时装入转储开始时刻的日志文件副本,利用恢复系统故障的方法将数据库恢复到某个一致性状态
  • 如果有后续的增量转储,按照从前往后的顺序,根据增量转储来修改数据库
  • 装入转储结束后的日志文件副本,重做已完成的事务
    • 首先反向扫描日志文件,找出故障发生时已经提交的事务,将事务标识符写入redo-list
    • 然后正向扫描日志文件,对redo-list中的所有事务进行redo操作