休止千鹤 | 我依旧是一名平凡的学生
这是一篇学习笔记,自己修改了一下,发出来吧。
这几个等级恢复可能性和发生可能性依次递减。恢复所需时间依次递增。
在历史记录中若$w1(A)<_H r2(A)<w2(B)<_H commit2$(事务1写入对象A然后事务2读取A,而后事务2写入B,最终事务2被提交)这种情况下T1(事务1)是不可重置的,因为T2读取了T1并且已经在最后提交。T2的结果很可能受到了T1的影响。试想我给你了100块钱是事务1,你又给了别人转了100块钱这是事务2。这个时候重置岂不是我100还有100块,别人白捡了100。
所以: T只能在其后事务读取后仍然没有提交的情况下才可以重置。
在历史记录中出现了$w1(A)<_H r2(A)<_H w2(B)<_H abort1$ 假设T2读到了T1刚刚在A中写的一个不合法的值,最后发现有问题,所以这下必须T2和T1都要回滚。
所以:一个事务终止时必须带着它读过的事务一起回滚回去。
这听起来太可怕了。但是它并不会影响到已经提交的事务。也就是说比如上述例子事务T2回滚前若T1已经提交(commit)或者被终止,那么级联终止就不会发生。
回滚事务的时候,我们当然希望每个单独的写操作都能回滚到写之前的样子(before image)。但是这样也可能导致错误。
比如: $w1(A)<_H w2(A)<_H abort1 <_H abort2$ 假设A是你的银行账户,原来有100块钱,事务1中你又存了一笔100,此时你账上有200了。事务二中你又想存一笔100,此时你应该账上有300块钱。可是这个时候事务1出了问题,表示要回滚,钱退你。回滚到事务1发生前,你原来有多少钱呢?100块钱,这好像有点不太对。还没完呢。这个时候事务2也出了问题喊着撤销,再退你100。这个时候嘛,200块钱也退你了。emmm好吧,没问题。就在你松口气的时候看了眼余额。你的账上却是200块钱!你之前明明只有100!
怎么回事?因为w2之前是200啊。你拿回了想存的200块钱,但是你的余额是200。你凭空账上多了100。
T1的运行终止留下了的无效值,被T2当做有效。
我们需要严格模式,T2必须等T1出了结果(提交或终止)后才执行。
我相信你们很多人都知道,数据库存储架构有两块: 一部分在内存里,另一部分在磁盘。硬盘访问一次的代价太大。内存中是一个缓冲区。数据库的常用部分临时存储在内存,比如对事务的操作等等,可以尽可能避免不必要的硬盘访问提高数据库性能。但是内存中也有个问题:断电数据就没了。
而数据库内存管理的单元是固定大小的单元管理数据库信息,而这通常被称为页(Page)。
如果你了解过mysql的InnoDB的内存,你会发现主要被分为Buffer Pool和Log Buffer。而Log Buffer就是为了做Redo Log。通常,一台Mysql数据库服务器会有很大的内存。而绝大多数内存都会被分给数据库服务。Buffer Pool越大,可以缓存更多的数据。更多的操作也会发生在内存,可以提高性能。我的博客系统没有用Mysql的原因是我的服务器只能租的起512M的内存,mysql显得有些臃肿。虽然mysql可以设置innodb_buffer_pool_size
但是我用了别的方案。这里不提。
关于缓存页何时写入硬盘有几个管理模式:
附一张表
force | no force | |
---|---|---|
steal | undo/keinRedo | undo/redo |
no steal | keinUndo/keinRedo | keinUndo/Redo |
我们可以知道,steal,no force的组合在运行的时候是最快速的。no steal, force的组合是最慢的。但是恢复起来情况相反。
这里引用慕尼黑大学 PD Dr. Peer Krög的讲义里的图:
简而言之,日志是由有序的,描述改动的条目:
一部分的日志在内存,一部分会被写入硬盘的日志文件。那些长久积攒的日志,会被归档起来。
日志会跟随者缓冲区的更新而更新。在进行恢复的时候,我们需要日志,看看当时做了什么操作。
哦,对了,如果你还记得恢复等级的话,那些硬盘里的日志文件用来做R1到R3恢复,至于归档,是用于R4恢复的。
事实上日志也有很多种。有逻辑日志,物理日志等等(Logical Log, Physical Log)。不过这里不提了。只是给ARIES的日志开个头。
(怎么翻译呢…利用语义的恢复和隔离算法?)
别被吓到。ARIES是一个恢复算法。可能你听着有点陌生,但是从当年的DB2到Oracle,mssql,mysql,postgresql都有ARIES的应用。
图来源于莱比锡大学讲义 Prof. E. Rahm 来源见最后参考
ARIES具有:
ARIES遵循WAL原则:
这样的话出现任何意外我们直接可以用日志进行回滚恢复。日志保证有,但是不知道还做没做就是了。这个不重要,因为恢复时还会写。
ARIES的日志有:[LSN, XID, PageID, Redo, Undo, PrevLSN]
(我这里的ARIES会是一个简化的ARIES,更好理解。实际上会复杂一些。)
CLR是Compensation Log Records 。你想,还是刚刚的例子。Redo做完了的时候,就像什么事都没发生一样。只是之前的事务后来要做啥,数据库也不知道。回滚,可以。但是如果回滚的时候老鼠又把电线咬了怎么办?谁知道回滚到哪里了。Redo只要有之前硬盘的数据和日志,都能还原“案发现场”,但是撤销那些事务做的事情的时候出了岔子就不好了。总得有个什么记着点吧。
于是有了CLR:[LSN, XID, PageID, Redo, PrevLSN, UndoNxtLSN]
和之前的日志对比,它少了Undo的信息,但是多了一个UndoNxtLSN。
CLR是一种特殊的日志。它可以把Undo也看做一种操作。我们刚刚说了Redo就是为了还原“案发现场”,那么Undo操作也是这案发现场的一部分,也可以被Redo还原就好了。没有Undo是因为CLR不需要Undo。至于UndoNxtLSN是为了保存恢复的进度,好让Undo一半崩溃掉的数据库再次恢复时可以接着做。
我们刚刚提到,分析,Redo的开始是一个Checkpoint。Checkpoint本身不难理解,你打游戏就有一堆Checkpoints,存档点。
我们认为Checkpoints之前都是好的。至于Checkpoint之后出了问题,就从Checkpoint恢复重来呗。没有存档点就很麻烦了。出了点问题,你就得整个重新再来。
但是Checkpoint设置是有点麻烦的。你想哦,设计多了,开销太大。设计少了,恢复就很麻烦;我们不想在Checkpoint把事务拆开,带着脏页。我们我们通常希望在没有事务活动的时候当做一个存档点。集中把页写进硬盘,整理一下日志什么的。但是哪有这么好的事?
事务一致Checkpoint
行为一致Checkpoint
Fuzzy Checkpoint
一文讲懂 ARIES Recovery 算法 写的很好了。推荐阅读。
Views:
Comments
(no comments...maybe you can be the first?)