Oracle完全检查点和增量检查点详解

  原文地址: http://hi.baidu.com/zty598416146/blog/item/3ab92b4f180f111fb2de0539.html

 

由于Oracle中LGWR和DBWR工作的不一致,Oracle引入了检查点的概念,用于同步数据库,保证数据库的一致性。在Oracle里面,检查点分为两种:完全检查点和增量检查点。下面我们分别介绍这两种检查点的作用:

1、完全检查点

在Oracle8i之前,数据库的发生的检查点都是完全检查点。完全检查点会将数据缓冲区里面所有的脏数据块写入相应的数据文件中,同时将最新的checkpoint scn更新到所有的数据文件头部及控制文件。保证数据库的处于一致的状态。需要注意的是,完 全检查点产生的时候,CKPT并不是把当前完全检查点发生那一时刻的SCN更新到控制文件和数据文件头,而是将这个触发检查点时刻DBWn当前刚写完 dirty buffer对应的SCN更新到控制文件和数据文件头,也就是说,更新控制文件和数据文件头的SCN是滞后于完全检查点的发生那一时刻的SCN的,这个从恢复的原理也很容易理解,因为检查点发生的时候要写入dirty buffer还没有写入,自然不能立即更新成当前的SCN了。需 要注意的是, 在oracle8之前,由于没有chekpoint  queue,也没有增量检查点的概念,发生完全检查点时,DBWn会以一种无序的方式将所有的 dirty buffer写出到数据文件,这个时候Oracle会冻结所有DML操作等候所有dirty  buffer被写出,巨大的IO往往会影响到数据库的性 能。后来随着Oracle数据库的发展和buffer  cache的不断增大,oracle 意识到这个单一的Full checkpoint机制已经不能满足需要,所以在Oracle 8i后提出增量检查点的概念,建立了checkpoint queue ,让dirty  buffer  header根据首次变化时候的顺序(LRBA)排列在queue里面。 这样DBWn只要顺着queue的顺序写,而其他进程不必等候dbwr的写完成就可以继续。  因此增量检查点的概念就由此产生了。

完全检查点在8i之后只有在下列两种情况下才会发生:

DBA手工执行alter system checkpoint的命令;

数据库正常shutdown (immediate,transcational,normal)。



2、增量检查点

说白了,就是

CKPT每3秒一次的检查DBWn写进度并在控制文件中记录检查点位置(checkpoint position)和更新heartbeat信息


以及

CKPT定期触发DBWn去写checkpoint queue中的脏数据

这两项操作合一起被称为增量检查点。 -->可能这块描述的过于笼统,大家继续往下看:-)

我们都知道被修改过的数据块,在oracle中都被统称为脏数据块(dirty buffer)。所有的脏块被一个链表串起来,称做检查点队列(checkpoint queue)。在buffer cache中,每一个块都有一个buffer header简称BH, 在BH中有一个ckptq项, 此项目中记录了指向检查点队列上一个块和下一个块的指针。 如果某一个块不在检查点队列中,他的ckptq项为空.通过ckptq项oracle将所有的脏块串成了一个双向链表。这个双向链表就是检查点队列了。

Oracle 从8i开始引入了检查点队列(checkpoint queue)的概念,用于记录数据库里面当前所有的dirty buffer的信息,这些dirty buffer的信息按被修改的时间先后存放在checkpoint queue里面(当块首次被更改时,块会立即被加进检查点队列),所涉及的条目主要包含RBA (Redo Block Address,重做日志里面用于标识事务期间数据块在重做日志里面发生更改的编号)和数据块的数据文件号和块号。

不 论数据块(buffer)更改几次,它在checkpoint queue里面的位置始终保持不变,checkpoint queue也只会记录它最早的RBA(这个最早的RBA其实就是Low RBA,也就是数据块第一次被修改时所对应的RBA),从而保证最早更改的数据块能够尽快从内存写入数据文件。DBWR每到一定的时机,就会被触发 (DBWn并不是只有当检查点发生的时候才写,它大约有10几种条件触发写操作),沿着检查点队列的顺序刷新脏块,同时CKPT进程,会监控着检查点队列 的长度,当检查点队列的长度达到一定限制时(具体有几个参数来确定checkpoing queue的长度,下面会提到比如log_checkpoint_timeout,fast_start_mttr_target等),CKPT会通知 DBWR写脏块。CKPT会根据几个参数的设置和I/O的速度以及繁忙程度,计算出来一个Target rba(目标rba),DBWn会沿着检查点队列,按照dirty buffer的Low RBA顺序将所有Target rba之前对应的脏块从内存写入数据磁盘文件。当CKPT通知完DBWn Target rba后,CKPT的任务就结束了。他并不会等待DBWn写完所有的Target rba之前的脏块。因此这里CKPT只是起到了一个通知DBWn进程写入的作用。

完全检查点发 生的时候,Oracle一方面通知DBWn进行下一批写操作,另一方面是将这个触发检查点时刻DBWn当前刚写完dirty buffer对应的SCN写入数据文件头和控制文件,这个SCN就是checkpoint scn。但Oracle考虑到检查点SCN的间隔还是太大了,因为检查点的触发条件有限,周期可能比较长,有些情况下比如检查点需要5分钟左右才触发,那 这个时候系统crash再重新启动就意味着很可能系统需要5分钟左右才能启动。于是Oracle采用了一个heartbeat的概念,以3秒的频率将 DBWn写的进度反应到控制文件中,这样系统crash重新启动的时候将从更近的一个时间点开始恢复。Oracle这么做的目的就是要缩短崩溃恢复时间! 因此CKPT另外一个任务就是每3秒,检测一次DBWn的写进度。DBWn 是沿着检查点队列写脏块,由于这里有一个顺序的关系,所以DBWn的写的进度就是可衡量的,写到哪个buffer的时候该buffer的首次变化时候的 scn(对应了LRba)就是当前所有数据文件block的上面最新scn,但是由于无法适时的将DBWn的进度记录下来,所以Oracle选择了一些策 略。 其中就包括CKPT进程的检查点位置更新和心跳,所以说CKPT每3秒钟查看一下DBWn沿检查点队列写到了哪里,并且将这个位置设置为检查点位置 (checkpont position)。也就是说检查点位置之前的块,都是已被DBWn刷新到磁盘上的块因此我们可以理解为,CKPT进程每3秒会根据DBWn写的进度设置并记录一个检查点位置,也就是说这个检查点位置就是由DBWn的在往Target RBA写过程中的进度决定的(如果没有dirty buffer产生,那么就不会更新检查点位置信息)。因 此CKPT每3秒会将检查点位置对应的数据块的rba (low cache rba-表示Instance Recovery时开始恢复的日志条目)更新和记录到控制文件的CHECKPOINT PROGRESS RECORDS区域,当然同时被记录进控制文件的还有heartbeat等其他信息。DBWn将检查点队列里面的dirty buffer写入到数据文件后,检查点的位置也要相应地往后移。


检 查点位置(checkpoint position)实际上就可以直接理解为是一个rba,他指向着重做日志文件中的某条重做记录。在此检查点位置前的重做记录,其对应的buffer cache中的dirty buffer已经被写进了数据文件,在此位置后的重做记录,所对应数据脏块有可能还在内存中。如果发生了实例崩溃,只需要在日志文件中找到检查点位置 (low cache rba),从此处开始应用所有的重做日志文件,就完成了前滚操作。实例崩溃后,再次启动数据库,oracle会到控制文件中读取low cache rba,这就是检查点位置。从此处开始应用重做日志,应用到on disk rba的位置。 on disk rba是磁盘中重做日志文件的最后一条重做记录的rba。 如 果某条重做记录的rba高于on disk rba,那说明此重做记录还没有被写进日志文件中,崩溃发生时,他是不可能被恢复的。on disk rba是oracle前滚操作的终点。比这个更高的rba,都应该还驻留在log buffer中。还没有被LGWR写入日志文件。所以是不能被用于恢复的。

在DBWn写dirty buffer这个检查点过程中,Oracle也可以继续产生dirty buffer,DBWn也不是一次要把所有dirty buffer全部写到磁盘(不同于完全检查点的地方),这样就提高了检查点的效率,使得数据库要做恢复的时候从这个最新位置开始做恢复,而不是从数据文件 中的checkpoint scn(上一个完全检查点位置) 开始做恢复,这样将缩短恢复时间。

Oracle  11g 的 Concept里面提到:An incremental checkpoint is a type of thread checkpoint partly intended to avoid writing large numbers of blocks at online redo log switches. DBWn checks at least every three seconds to determine whether it has work to do. When DBWn writes dirty buffers, it advances the checkpoint position, causing CKPT to write the checkpoint position to the control file, but not to the  data  file headers.
因此我们需要注意的是: 增量检查点并不会去更新数据文件头,以及控制文件中数据库SCN以及数据文件条目的SCN信息,而只是每3秒由CKPT进程去更新控制文件中的low cache rba信息,也就是检查点的位置。

检查点位置发生变更后, Oracle主要通过4个参数和1个机制来控制检查点位置和最后的重做日志条目之间的距离(检查点队列的长度)。

fast_start_io_target (Oracle 9i以后已经废弃)

该 参数用于表示数据库发生Instance Recovery的时候需要产生的IO总数,它通过v$filestat的AVGIOTIM来估算的。比如我们一个数据库在发生Instance Crash后需要在10分钟内恢复完毕,假定OS的IO每秒为500个,那么这个数据库发生Instance Recovery的时候大概将产生500*10*60=30,000次IO,也就是我们将可以把fast_start_io_target设置为 30000。

fast_start_mttr_target

我 们从上面可以看到fast_start_io_target来估算检查点位置比较麻烦。Oracle为了简化这个概念,从9i开始引入了 fast_start_mttr_target这么一个参数,用于表示数据库发生Instance Recovery的时间,以秒为单位。这个参数我们从字面上也比较好理解,其中的mttr是mean time to recovery的简写,如上例中的情况我们可以将fast_start_mttr_target设置为600。注意当设置了 fast_start_mttr_target后, fast_start_io_target这个参数将不再生效,从9i后 fast_start_io_target这个参数被Oracle废除了。

log_checkpoint_timeout

该参数用于表示检查点位置和重做日志文件末尾之间的时间间隔,以秒为单位,默认情况下是1800秒。 相 比fast_start_mttr_target,它也是时间,但它的时间值表示完成恢复操作所需要的时间,即从最后的检查点位置开始,应用所有日志直到 日志末尾所需要的时间。而本参数log_checkpoint_timeout表示从最后的检查点位置开始,到日志末尾经过的时间。

log_checkpoint_interval

该参数是表示检查点位置和重做日志末尾的重做日志块的数量,以OS块表示。

90% OF SMALLEST REDO LOG


除了以上4个初始化参数外,Oracle内部事实上还将重做日志文件末尾前面90%的位置设为检查点位置。在每个重做日志中,这么几个参数指定的位置可能不尽相同,Oracle将离日志文件末尾最近的那个位置确认为检查点位置。

在Oracle 9i后,对检查点频率,建议只设置fast_start_mttr_target。根据需要,也可以通过设置 log_checkpoint_timeout,设置一个脏块保持脏状态的最大时间,而其他两个参数 fast_start_io_target,log_checkpoint_interval建议不再使用。

你可能感兴趣的:(oracle)