数据库事务处理技术-故障恢复

第23讲 数据库事务处理技术-故障恢复

数据库的故障类型及其影响

典型的数据库故障

  • 事务故障
    某一个程序(事务)自身运行错误所引起的故障
    影响该程序(事务)本身

  • 系统故障

    由于掉电、非正常关机等所引起的故障
    影响正在运行的事务以及数据库缓冲区, 数据库缓冲区将涉及正在 运行和已经运行的事务

  • 介质故障

    由于介质损坏等所引起的 故障
    影响是全面的,既影响内存中的数据, 又影响介质 中存储的数据

数据库故障恢复的宏观思路

三种类型故障:事务故障、系统故障和介质故障
三种恢复手段: 事务的撤消与重做, 运行日志和备份
两个重要时刻:检查点和转储点

每个事务都会读写某些元素

READ(X,t):将元素X读到事务的局部变量t中;

WRITE(X,t):将事务局部变量t写回元素X;

INPUT(X):将元素X从磁盘读入到内存缓冲区中;

OUTPUT(X):将元素X写回到磁盘中。

每个事务都以提交或者撤销结束

COMMIT:事务提交

ABORT:事务撤销

DBMS在故障发生时需要保障事务

  1. 持久性

    • 已提交的事务——缓冲区内容保证写回磁盘
    • 未提交的事务——缓冲区内容不能影响磁盘
  2. 原子性

    事务的所有操作,要么全都执行,要么全不执行。

注意:缓冲区内容和磁盘内容并不是时刻保持一致的。

不同缓冲区策略

Force:内存中的数据最晚在commit的时候写入磁盘。

No steal:不允许在事务commit之前把内存中的数据写入磁盘。

No force:内存中的数据可以一直保留,在commit之后过一段时间再写入磁盘。此时在系统崩溃的时候可能还没写入到磁盘,需要Redo,此方式较为灵活。

Steal:允许事务commit之前把内存中的数据写入磁盘,此时若系统在commit之前崩溃时,已经有数据写入到磁盘了,要恢复到崩溃前的状态,需要Undo,此方式同样较为灵活。

当前最常用:Steal + No force

什么是日志?

一个包含日志记录的、只能追加的顺序文件, 不同事务的日志记录交错存储,按发生时间存储。

发生系统故障时,使用日志进行恢复:

故障时已提交的事务,重做(Redo)

故障时未提交的事务,撤销(Undo)

Undo型日志及其故障恢复

对于任一事务T,按下列顺序向磁盘输出T的日志信息:
首先,<T, X, v>被写到日志中
其次,OUTPUT(X)
最后,被写到日志中
注意:Undo型日志仅保留旧值。<T, X, v>,v为X原来的值(X的旧值)
Undo型日志:“将事务改变的所有数据写到磁盘前不能提交该事务”

利用undo型日志进行恢复
首先,确定每一个事务是否已完成?

1
2
3
4
5
6
7
8
<START T>….<COMMIT T>….	= yes
<START T>….<ABORT T>……. = no(已结束,但未完成)
<START T>……………………… = no
然后,从日志的尾部开始按日志记录的反序,处理每一日志 记录,撤销未完成事务的所有修改
<COMMIT T>: 标记T已完成
<ABORT T>: 标记T已结束但未完成
<T,X,v>: 如果T未完成,则将X=v写回磁盘;否则跳过;
<START T>: 跳过

检查点及其使用

  • 静止检查点:

    周期性地对日志设置检查点
    停止接受新的事务, 等到所有当前活跃事务提交或终止,并在日志中 写入了COMMIT或ABORT记录后
    将日志刷新到磁盘,写入日志记录,并再次刷新日志

  • 非静止检查点
    在设置检查点时不必关闭系统,允许新事务进入
    写入一条<START CKPT(T1,…,Tk)>
    其中T1,…,Tk 是所有活跃的未结束的事务
    继续正常的操作,直到T1,…,Tk都完成时,写入

故障需恢复到所 遇到的第一个检查点

Redo型日志及其故障恢复

Redo型日志
Undo型日志的问题“将事务改变的所有数据写到磁盘前不能 提交该事务”—如何解决?
对于任一事务T,按下列顺序向磁盘输出T的日志信息:

1
2
3
4
5
6
首先,<T, X, v>被写到日志中
其次,<COMMIT T>被写到日志中
最后,OUTPUT(X)
注意:redo型日志保留新值。<T, X, v>,v为X更新后的值(X的新值)
注意:与undo型的差别,在后两步,先写提交记录后输出,还是先输
出,再写提交记录。

利用redo日志进行恢复
确定每一个事务是否已完成?

1
2
3
4
<START T>….<COMMIT T>…. =yes

<START T>….<ABORT T>…….=no(已结束,但未完成)
<START T>……………………… = no

从日志的起始位置开始按日志记录的正序处理每一日志记录,重做已提交事务的所有修改:

1
2
3
4
<COMMIT T>:	标记T已完成
<ABORT T>:标记T已结束但未完成
<T,X,v>: 如果T已完成,则将X=v写回磁盘;否则跳过;
<START T>: 跳过

检查点

  • 非静止检查点
    在进行检查点设置时不必关闭系统,允许新事务进入
    写入一条<START CKPT(T1,…,Tk)>
    其中T1,…,Tk 是所有活跃的未结束的事务
    将所有已提交的事务写回磁盘,
    继续正常的操作,直到T1,…,Tk都完成时,写入

Undo/Redo结合型日志及其故障恢复

Redo型日志与Undo型日志的比较

Undo型日志:

  • OUTPUT必须先做。

  • 如果可见, T确定地已将所有其数据写回磁盘,因此不必重做 –– 但可能引起性能下降(因可能频繁地写磁盘)

Redo型日志:

  • OUTPUT必须后做。

  • 如果不可见, T确定地没有将其任何数据写回到磁盘, 因此无需撤销 –– 但灵活性差(数据必须在Commit后才可见)

如更喜欢灵活性 – 需要采用Undo/Redo型日志

Undo/Redo型日志
对于任一事务T,按下列顺序向磁盘输出T的日志信息:

1
2
3
4
- 第(1)步,<T, X, u, v>被写到日志中
- 第(2)or(3)步,<COMMIT T>被写到日志中
- 第(3)or(2)步,OUTPUT(X)
- 注意:undo/redo型日志既保留新值v,也保留旧值u。

注意:与undo型和redo型的差别,在后两步。

Redo型是先写提交记录 后输出;

undo型是先输出,再写提交记录;

undo/redo型则无所谓谁先谁 后,只要保证<T,X,u,v>被先于OUTPUT写完即可。

利用undo/Redo型日志进行恢复

首先,确定每一个事务是否已完成?

1
2
3
<START T>….<COMMIT T>….	= yes
<START T>….<ABORT T>……. = no(已结束,但未完成)
<START T>……………………… = no

自前向后地,按日志记录的正序,重做所有已提交的事务;

自后向前,按日志记录的反序,撤销所有未完成事务的所有修改。

1
2
3
4
<COMMIT T>:	标记T已完成
<ABORT T>:标记T已结束但未完成
<T,X,u,v>: 如果T未完成,则将X=u写回磁盘;否则将x=v写回磁盘;
<START T>: 跳过

总而言之:自后向前地撤销所有未提交的事务;自前向后地重做所有已提交的事务;先做<撤销>,再做<重做>


转载无需注明来源,放弃所有权利