摘要/数据库/Redis/Log

what

Redo Log与Undo Log是系统恢复的基础前提

系统恢复时,undo需要redo的配合来实现。

redo日志有commit或者abort记录时,事务是无需undo的。

Redo Log

what

Redo Log以顺序附加的形式记录新值。

幂等。

why

Redo用来保证事务的原子性持久性

how

记录<T,X,V>,表示事物T将新值V存储到数据库元素X。

新值可以保证重做

一个事务从开始到结束,要么提交完成,要么中止,具有原子性。

事务无关性,根据日志统一redo,之后的撤销工作交给undo来进行。

Undo Log

what

Undo记录通常以随机操作的形式记录旧值。

逻辑日志,并不幂等。

撤销时,根据undo记录进行补偿操作。undo本身也产生redo记录。通过undo日志数据库可以实现MVCC(Multi-Version Concurrency Control 多版本并发控制)。保证了事务失败或者主动abort时的机能,系统崩溃恢复时,也确保数据库状态能恢复到一致。

why

Undo能保证事务的一致性

how

记录<T1,Y,9>,表示事物T1对Y进行了修改,修改前Y的值是9。

旧值能用于撤销,也能供其他事务读取

 

CheckPoint检查点

what

分类

简单检查点

停止接受新的事务->等待当前所有活跃事务完成或中止,并在日志中写入commit或abort记录->当前位于内存的日志,将缓冲块缓存到磁盘->写入日志记录<CKPT>,再次刷新到磁盘。->重新开始接受事务,系统恢复。

从日志尾端反向搜索,直到找到第一个<CKPT>标志并处理。

非静止检查点

检查过程中允许接受新事物进入。

将一个点扩展到一个处理区间。(JVM的GC处理从Stop the world 到安全区的处理)

写入日志记录<START CKPT(t1,...tn)>,其中t1,...tn所有的事务都已完成,写入日志记录<END CKPT>

从日志尾端反向搜索。

先遇到<START CKPT(t1,...tn)> 系统在检查点过程中崩溃

未完成事务的部分:

(t1,...t2)记录的部分以及<START>标志后新进入的部分

这部分事务最早的那个事务的开始点就是扫描的截止点,再往前可以不必扫描。

先遇到<END CKPT> 系统完成了上一个周期的检查点,新的检查点还没开始。

需要处理的事务:

<END CKPT>标志之后到系统崩溃这段时间内的事务以及上一个<START>,<END>区间内新接受的事务。

为此,扫描到上一个检查点<START CKPT()>就可以截止。

why

日志很长时,搜索过程太耗时。

redo是幂等的,大多数需要重做的事务已经把更新写入,恢复过程会变得很长。

一旦事务commit日志记录写入磁盘,逻辑上而言,本事务的undo记录在恢复时已经不需要,在commit时可以删除之前的undo记录。但由于多事务同时执行,其他事务可能仍在使用undo中的旧值,因此需要checkPoint来处理这些当前活跃的事务。

why

 

how

写日志

直接写入到存储介质

等待一次IO。

fsync函数。

先写到缓存,在之后的某一时间点统一写入磁盘

 

存储数据

方案一

操作流程简单如下(假设每次数据变化,都提交):

  1. 更新的操作方式依次记录到磁盘日志文件。(如果在写操作作日志的时候发生故障,那么这次数据库操作失败)
  2. 更新内存中的数据。
  3. 返回更新成功结果。

恢复流程:

  1. 读取日志文件,依次修改内存中的数据。

优点:

  1. 日志文件有序,可以通过append的方式写入磁盘,性能很高。
  2. 简单可靠,应用广泛。可以把内存中的数据,做备份在磁盘中。

缺点:

  1. 使用时间一长,恢复宕机的时间很慢。

 

方案二

操作流程:

  1. 日志文件记录begin check point
  2. 在某个时刻,把内存中的数值,直接snapshot或dump到磁盘上。(比如直接记录a=4)
  3. 日志文件记录end check point

恢复流程:

  1. 扫描日志文件,找到最后的end check point中配对的begin check point
  2. 读入dump文件。
  3. 依次回放记录的日志操作。

优点:

  1. 应用广泛,包括 mysql,oracle。

一些棘手的问题:

  1. 在做snapshot的时候,往往不能停止数据库的服务,那么很可能记录了begin check point之后的日志。
  2. 那么在重新load begin check point之后的日志时,最后恢复的数据很有可能不对。比如记录的是a++这样的日志, 那么重复一条日志,就会让a的值加1。反之如果记录是幂等的,比如一直是 a=5 这种操作,那么就对最后结果没有影响。

很显然,设计幂等操作系统很麻烦。

  1. 设计一个支持snapshot的内存数据结构,也比较麻烦。

典型的是通过copy-on-write机制。和操作系统中的概念一样。当这个数据结构被修改,就创建一份真正的copy。老数据增加一份dirty flag。如果没有修改就继续使用之前的内存。这样在做snapshot的时候,保证我们的dump数据是begin check point这个时刻的数据。显然这个也比较麻烦。

还有一种支持snapshot的思路是begin check point后,不动老的数据。内存中的数据在新的地方,日志也写在新的地方。最后在end check point做一次merge。这个实现起来简单,但是内存消耗不小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值