Oracle Redo Log 机制 小结(二)

2014-11-24 17:13:06 · 作者: · 浏览: 1
OG BUFFER 中写入REDO LOG 文件,此时事务提交成功的信号才能发送给用户进程。通过这个机制,可以确保哪怕这个已经提交的事务中的部分BUFFER CACHE 还没有被写入数据文件,就发生了实例故障,在做实例恢复的时候,也可以通过REDO LOG 的信息,将不一致的数据前滚。



既确保数据库性能不会下降,又保证实例恢复的快速,解决这个问题,oracle是通过checkpoint 机制来实现的。


Oracle 数据库中,对BUFFER CAHCE 的修改操作是前台进程完成的,但是前台进程只负责将数据块从数据文件中读到BUFFERCACHE 中,不负责BUFFERCACHE 写入数据文件。BUFFERCACHE 写入数据文件的操作是由后台进程DBWR 来完成的。DBWR 可以根据系统的负载情况以及数据块是否被其他进程使用来将一部分数据块回写到数据文件中。这种机制下,某个数据块被写回文件的时间可能具有一定的随机性的,有些先修改的数据块可能比较晚才被写入数据文件。



而CHECKPOINT 机制就是对这个机制的一个有效的补充,CHECKPOINT 发生的时候,CKPT 进程会要求DBWR 进程将某个SCN 以前的所有被修改的块都被写回数据文件。这样一旦这次CHECKPOINT 完成后,这个SCN 前的所有数据变更都已经存盘,如果之后发生了实例故障,那么做实例恢复的时候,只需要冲这次CHECKPOINT 已经完成后的变化量开始就行了,CHECKPOINT 之前的变化就不需要再去考虑了。



这里引入一个名词:Write-Ahead-Log,就是日志写入优先。日志写入优先包含两方面的算法:


第一个方面是,当某个BUFFER CACHE 的修改的变化矢量还没有写入REDO LOG 文件之前,这个修改后的BUFFER CACHE 的数据不允许被写入数据文件,这样就确保了再数据文件中不可能包含未在REDO LOG 文件中记录的变化;


第二个方面是,当对某个数据的UNDO 信息的变化矢量没有被写入REDOLOG 之前,这个BUFFERCACHE的修改不能被写入数据文件。







REDO LOG是顺序写的文件,每次写入的数据量很小,TEMP文件虽然也就有部分顺序读写的特点,但是TEMP每次读写的数据量较大,和REDO 的特性不同。UNDO是典型的随机读写的文件,索引更是以单块读为主的操作。



REDO LOG 的产生十分频繁,几乎每秒钟都有几百K 到几M 的RED LOG 产生,甚至某些大型数据库每秒钟产生的REDO LOG 量达到了10M 以上。不过前台进程每次产生的REDO量却不大,一般在几百字节到几K,而一般一个事务产生的REDO 量也不过几K到几十K。



基于REDO 产生的这个特点,如果每次REDO产生后就必须写入REDOLOG 文件,那么就会存在两个问题,一个是REDO LOG 文件写入的频率过高,会导致REDO LOG文件的IO 存在问题,第二个是如果由前台进程来完成REDO LOG 的写入,那么会导致大量并发的前台进程产生REDO LOG 文件的争用。



为了解决这两个问题,Oracle 在REDO LOG 机制中引入了LGWR 后台进程和LOGBUFFER。


LOG BUFFER 是Oracle 用来缓存前台进程产生的REDO LOG 信息的,有了LOG BUFFER,前台进程就可以将产生的REDO LOG 信息写入LOG BUFFER,而不需要直接写入REDO LOG 文件,这样就大大提高了REDO LOG 产生和保存的时间,从而提高数据库在高并发情况下的性能。既然前台进程不将REDOLOG 信息写入REDO LOG 文件了,那么就必须要有一个后台进程来完成这个工作。这个后台进程就是LGWR,LGWR 进程的主要工作就是将LOG BUFFER 中的数据批量写入到REDO LOG 文件中。对于Oracle 数据库中,只要对数据库的改变写入到REDO LOG 文件中了,那么就可以确保相关的事务不会丢失了。



引入LOG BUFFER 后,提高了整个数据库RDMBS 写日志的性能,但是如何确保一个已经提交的事务确确实实 被保存在数据库中,不会因为之后数据库发生故障而丢失呢?实际上在前面两节中我们介绍的REDO LOG 的一些基本的算法确保了这一点。


首先WRITE AHEAD LOG 协议确保了只要保存到REDO LOG 文件中的数据库变化一定能够被重演,不会丢失,也不会产生二义性。其次是在事务提交的时候,会产生一个COMMIT 的CV,这个CV 被写入LOG BUFFER 后,前台进程会发出一个信号,要求LGWR 将和这个事务相关的REDO LOG 信息写入到REDO LOG 文件中,只有这个事务相关的REDO LOG 信息已经确确实实被写入REDO LOG 文件的时候,前台进程才会向客户端发出事务提交成功的消息,这样一个事务才算是被提交完成了。在这个协议下,只要客户端收到了提交完成的消息,那么可以确保,该事务已经存盘,不会丢失了。



LGWR 会绕过操作系统的缓冲,直接写入数据文件中,以确保REDO LOG 的信息不会因为操作系统出现故障(比如宕机)而丢失要求确保写入REDO LOG 文件的数据。



实际上,虽然Oracle 数据库使用了绕过缓冲直接写REDO LOG 文件的方法,以避免操作系统故障导致的数据丢失,不过我们还是无法确保这些数据已经确确实实被写到了物理磁盘上。因为我们RDBMS 使用的绝大多数存储系统都是带有写缓冲的,写缓冲可以有效的提高存储系统写性能,不过也带来了另外的一个问题,就是说一旦存储出现故障,可能会导致REDO LOG 的信息丢失,甚至导致REDO LOG 出现严重损坏。存储故障的概率较小,不过这种小概率事件一旦发生还是会导致一些数据库事务的丢失,因此虽然Oracle 的内部算法可以确保一旦事务提交成功,事务就确认被保存完毕了,不过还是可能出现提交成功的事务丢失的现象。



实际上,Oracle 在设计REDO LOG 文件的时候,已经最大限度的考虑了REDO LOG 文件的安全性,REDO LOG 文件的BLOCK SIZE 和数据库的BLOCK SIZE 是完全不同的,REDO LOG 文件的BLOCK SIZE 是和操作系统的IO BLOCK SZIE 完全相同的,这种设计确保了一个REDO LOG BLOCK 是在一次物理IO 中同时写入的,因此REDOLOG BLOCK 不会出现块断裂的现象。