恢复机制是数据库系统必不可少的组成部分,它负责将数据库恢复到故障发生前的一致的状态
高可用性:必须将数据库崩溃后不能使用的时间缩减到最短
故障分类:
* 事务故障:
1 逻辑错误,
2 系统错误,如死锁
* 系统崩溃
* 磁盘故障
恢复算法:
1 在正常事务处理时采取措施,保证有足够的信息可用于故障恢复
2 故障发生后采取措施,将数据库内容恢复到某个保证数据库一致性、原子性及持久性的状态
存储器:
稳定存储器的实现:
需要在多个非易失性存储介质上以独立的故障模式复制所需信息,并且以受控方式更新信息。
在内存和磁盘存储器间进行块传送有以下几种可能:
1 成功完成
2 部分失败,目标块有不正确信息
3 完全失败,故障发生的足够早,目标块仍完好无缺
要求数据传送故障时,系统能检测到并且调用恢复过程将块恢复成为一致的状态,
输出操作执行如下:
1 将信息写入第一个物理块
2 当第一次写成功完成时,将相同信息写入第二个物理块
3 只有第二次写成功完成时,输出才算完成
数据访问:
恢复与原子性:
为了保持原子性的目标,我们必须在修改数据库本身之前,首先向稳定存储器输出信息,描述要做的修改
日志记录:
日志是日志记录的序列 ,它记录数据库中的所有更新活动
日记记录有几种,更新日志记录描述一次数据库写操作,它具有如下几个字段:
1 事务标识:是执行write操作的事务的唯一标识
2 数据项标识:所写数据项的唯一标识,通常是数据项在磁盘上的位置,包括数据项所驻留的块地块标识和块内偏移量
3 旧值:是数据项的写前值
4 新值:是数据项的写后值
将一个更新日志记录表示为<a,b,c,d>,表明事务a对数据项b执行一个写操作,旧值是c,新值是d
一些日志记录类型:
1 <a start>
2 <a commit>
3 <a abort>
数据库修改:
事务在进行数据项修改中所采取的步骤:
1 事务在主存中对自己私有的部分执行某些计算
2 事务修改主存的磁盘缓冲区中包含该数据项的数据块
3 数据库系统执行output操作,将数据块写到磁盘中
如果一个事务直到它提交时都没有修改数据库,我们说它采用了延迟修改技术
如果数据库修改在事务仍然活跃时发生,我们就说它采用了立即修改技术
恢复算法必须考虑多种因素,如:
1 有可能一个事务已经提交了,虽然它所做的某些数据库修改还仅仅存在于主存的磁盘缓冲区中,而不在磁盘上的数据库中
2 有可能出于活动状态的一个事务已经修改了数据库,而作为后来发生的故障的结果,这个事务需要中止
由于所有的数据库修改之前必须建立日志记录,因此系统有数据项修改前的旧值和要写给数据项的新值可以用
系统执行适当的undo和redo操作:
1 undo:使用一个日志记录,将该日志记录中指明的数据项设置为旧值
2 redo:使用一个日志记录,将该日志记录中指明的数据项设置为新值
并发控制和恢复:
并发控制模式有可能两个事务同时影响一个数据项
为避免这样的情形发生,恢复算法通常要求如果一个数据项被一个事务修改了,那么在该事务提交或中止前不允许其他事务修改该项
这一要求可以通过对更新的数据项获取排他锁
事务提交:
当一个事务的commit日志记录——该事务的最后一个日志记录——输出到稳定存储器后,我们就说这个事务提交了
对于大多数基于日志的恢复技术,包括本章描述的技术,不是在一个事务提交时必须将包含该事务修改的数据项的块输出到稳定存储器中,可以在以后的某个时间再输出
使用日志来重做和撤销事务:
发生系统崩溃之后,系统查阅日志以确定为保证原子性需要对哪些事务进行重做,对哪些事务进行撤销:
1 如果日志包括<T start>记录,但即不包括<T commit>,也不包括<T abort>记录,则需要对事务T进行撤销
2 如果日志包括<T start>记录,以及<T commit>或<T abort>记录,需要对事务进行重做
检查点:
需要搜索整个日志来确定该信息,这样做有两个主要的困难:
1 搜索过程太耗时
2 根据算法,大多数需要重做的事务已把其更新写入数据库中,尽管对它们重做不会造成不良后果,但是恢复过程太长
为了降低开销,引入检查点
检查点的执行过程如下:
1 将当前位于主存的所有日志记录输出到稳定存储器
2 将所有修改的缓冲块输出到磁盘
3 将一个日志记录<checkpoint L>输出到稳定存储器,其中L是执行检查点时正活跃的事务的列表
在检查点执行过程中时,不允许事务执行任何更新动作
系统发生崩溃后,只需要对L中的事务,以及<checkpiont L>记录写到日志中之后才开始执行的事务进行undo或redo
恢复算法:
事务回滚:
1 从后往前扫描日志,对于所发现的T的每一个日志记录<T,X,V1,V2>:
a 值V1被写到数据项X中
b 往日志中写一个特殊的只读日志记录<T,X,V>,其中V是在本次回滚中数据项X恢复成的值
2 一旦发现<T,start>日志记录,就停止从后往前的扫面,并往日志中写一个<T,abort>日志记录
系统崩溃后的恢复:
恢复动作分两阶段进行:
1 在重做阶段:系统通过从最后一个检查点开始正向地扫描日志来重做所有事务的更新,具体步骤如下:
a 将要回滚的事务的列表undo-list初始设定为<checkpoint L>日志记录中的L列表
b 一旦遇到形为<T,X,V1,V2>的正常日志记录或形为<T,X,V2>的redo-only日志记录,就重做这个操作
c 一旦发现<T,start>的日志记录,就把T加到undo-list中
d 一旦发现<T,abort>或<T,commit>的日志记录,就把T从undo-list中去掉
在末尾,undo-list包括在系统崩溃之前尚未完成的所有事务,
2 在撤销阶段:系统回滚undo-list中的所有事务,它通过从尾端开始反向扫描日志来执行回滚
a 一旦发现undo-list中的事务的日志记录,就执行undo操作,就像在一个失败事务的回滚过程中发现了该日志记录一样
b 当发现了T的<T,start>日志记录,它就往日志中写一个<T,abort>日志记录,并且把T从undo-list中去掉
c 一旦undo-list为空,则撤销结束
缓冲区管理:
日志记录缓冲:
将一个块输出到稳定存储器的开销非常高,因此最好是一次输出多个日志记录,为了达到这个目的,将日志写到主存的日志缓冲区
由于系统崩溃时这种日志记录会丢失,我们必须对恢复技术增加一些要求以保证事务的原子性:
1 将日志记录<T commit>输出到稳定存储器后,事务T进入提交状态
2 将日志记录<T commit>输出到稳定存储器前,与事务T有关的所有日志记录必须已经输出到稳定存储器
3 在主存中的数据块输出到数据库前,所有与该数据块中数据有关的日志记录必须已经输出到稳定存储器
这一条规则称为先写日志规则
数据库缓冲:
强制策略:期望事务在提交时强制地将修改过的所有的块都输出到磁盘
非强制策略:即一个事务修改了某些还没有写回到磁盘的块,也允许它提交
恢复算法在即使是非强制策略的情况下也能正确工作
锁的提前释放和逻辑undo操作:
逻辑操作:
插入和删除操作是这一类操作的例子,它们需要逻辑undo操作,因为它们提前释放锁,我们把这样的操作称为逻辑操作
操作在执行时需要获得低级别的锁,操作完成就释放锁,
然而相应的事务必须按两阶段方式保持高级别的锁,以防止并发事务执行冲突动作
一旦释放了低级别的锁,就不能用更新的数据项的旧值来对操作进行撤销,而必须通过执行一个补偿操作来撤销,称为逻辑undo操作
逻辑undo日志记录
要允许操作的逻辑undo,在执行修改索引的操作之前,事务创建一个<T,Q,operation-begin>日志记录,
其中Q是该操作实例的唯一标识。
当操作结束时,它写一个形如<T,Q,operation-end,U>的记录,其中u标识undo信息
记关于操作的这类信息的日志称作逻辑日志
记关于旧值和新值信息的日志称作物理日志,对应的日志记录称作物理日志记录
逻辑日志仅用于撤销,不用于重做
有逻辑undo的事务回滚:
1 在扫描中遇到的物理日志记录像以前描述的那样处理,使用由操作产生的物理日志记录对不完全的逻辑操作进行撤销
2
ARIES
远程备份系统: