oracle介质恢复和实例恢复总结
前几天解决一个控制文件版本过旧的问题,由此引发我对oracle恢复的诸多思考。
1、控制文件恢复,这中间到底做了哪些事情?
2、recover database在什么时候使用,后面的参数又有什么意义?
3、介质恢复和实例恢复的区别是什么,恢复过程又是怎样的?
4、oracle 的redo中到底记录了哪些东西?
5、为什么要用alter database open resetlogs?
6、控制文件中几个scn号之间的关系呢?
7、oracle判断控制文件过旧的机制?
8、RBA是什么时候产生的?
9、增量检查点和完全检查点区别?
10、........
各种SCN概念介绍
在说明这些个问题之前,先说一下oracle实例恢复和介质恢复吧。我们知道oracle的启动分为3个阶段,那么在open阶段需要进行一致性检查(当然也可以绕过)。在一致性检查中涉及到4个scn号,分别是:
①系统SCN:system checkpoint SCN,系统每发生一次checkpoint,就会把current_scn更新到系统全局scn;
②控制文件记录的数据文件头SCN:控制文件中记录的数据文件头的scn号 ;
③数据文件自己头部的SCN(start SCN):指的是数据文件物理意义上的scn号
④控制文件中记录的数据文件结束SCN,即end SCN:在oracle正常运行时,这个值为空,而在控制文件中记录的这个值是无穷大(16进制:0xfffffffff...);在oracle正常关闭时,会把current_scn更新到end SCN。所以当oracle非正常关闭时,这个end SCN是来不及更新的,再次启动数据时会发现控制文件中记录的这个值是无穷大。
在数据文件头和控制文件中都记录着完全检查点计数checkpoint cnt,每发生一次完全检查点,这个值加1。cnt的递增和scn的更新是在完全检查点发生的,下面会说到full checkpoint。
介质恢复和实例恢复的区别是什么,恢复过程又是怎样的?
所谓实例恢复又叫做崩溃恢复。数据库在突然崩溃的那一刹那,可能会发生已经提交的数据没有写入到磁盘,可能没有提交的数据已经写入到磁盘。那么这些数据都是不正常的,要保证一致性,就要对这些数据进行恢复。实例恢复是由smon进程完成的,不需要人为操作。
①已经提交的数据没有写入到磁盘,需要前滚
更改的操作已经提交了,那么其对应的数据块的修改过程必然写入到redo,重做即可。问题是哪些redo需要重做呢?上面说到在每一次ckpt rba之前的日志信息对应的脏数据是一定会被写入到磁盘的,在次之后的日志信息对应的脏数据是没有写入到磁盘的。那么我们的恢复就是最后一次的checkpoint RBA到最后一次日志写入磁盘的on_disk rba这之间的redo。这两个rba在控制文件中都有记录。
②没有提交的数据已经写入到磁盘,需要回滚
上面已经说到,如何找到需要回复的redo,在这段redo中存在着事物对数据修改的undo信息,拿到这段undo信息恢复即可。
当你发现你的数据文件是备份的,那么从数据文件备份那一刻到当前数据库这段期间的数据改变都会丢失,此时便需要介质恢复。此时就不能用rba信息来确定需要的redo了,而是以当前数据文件头的scn开始,到当前redo最新的scn为结束点,找到这段redo重做即可,也有可能会用到归档。(之前和同事讨论是不是以当前数据文件头的scn为开始点,我的想法是在这个scn之前产生的所有redo是否都已经体现在数据文件中了?)
控制文件中几个scn号之间的关系呢?
在数据库open的过程中,Oracle要进行两次检查 (实际情况要复杂很多,这里只是简要说明。也许只有Oracle的开发人员才知道到底要做哪些事情~~~).
第一次检查数据文件头中的Checkpoint cnt是否与对应控制文件中的Checkpoint cnt一致.
如果相等 (注:其实如果相等,则System Checkpoint SCN = Datafile Checkpoint SCN = Start SCN,当然只读表空间除外), 进行第二次检查.
第二次检查数据文件头的开始SCN和对应控制文件中的结束SCN是否一致
如果结束SCN等于开始SCN,则不需要对那个文件进行恢复 (注:如果不等,即Stop SCN为无穷大,则需要Istance Recovery).
(编者注:这里的open过程的说法和我前面转载的关于SCN的文章不尽相同,但是我个人理解第一次就是做是否需要Media Recovery的检查;第二次就是做是否需要做Instance Recovery的检查。第一步如果文件版本不一致,就开始做Media Recover,根据相应的SCN确定需要的log;如果不需要Media Recovery,则检查是否需要Instance Recovery,如果Stop SCN的值为无穷大,则需要,而且要提交redo logs直到最新的那一个)
RBA是什么时候产生的?
当database buffer cache里的1个buffer 被修改时, 也就是被变脏时就会产生日志, 而这些日志为被写入到Log buffer cache(日志缓存里), 那么这些日志在日志缓存里的位置就是RBA了.而脏buffer会把对把对应的RBA记录在自己的头部信息中, 当这个脏buffer要被回滚时, server process就可以根据RBA找到对应的日志了。而1个buffer的RBA并不是唯一的。由于1个buffer可以在不同的时间段被多次修改, 就会产生多次日志, 而这些日志会被写入到log buffer cache中的不同的位置。所以往往1个buffer里面记录着多个RBA。
增量检查点和完全检查点
首先让我们先来总结一下用户修改块时,Oracle内部都发生了什么:
1、如果块不在Buffer cache,将块读入Buffer cache
2、先生成重做记录,并记入日志缓存,在用户提交时写到日志文件中
3、在Buffer cache中修改块
4、在Buffer cache中设置块的脏标志位,标志块变成脏块,同时在检查点队列末尾增加一个新节点,记录这个新脏块的信息,信息包括:脏块在Buffer cache中的位置,在步骤2时生成的与此脏块对应的重做记录位置。
5、用户提交后,将相应的重做记录从重做缓存写入日志文件。
在8i之前,Oracle定期的锁住所有的修改操作,刷新Buffer cache中的所有脏块,这种刷新脏块的方式被称为完全检查点,这极大的影响了效率。
完全检查点工作方式是先记下当前的scn, 将此scn之前所有的脏块一次性写完,再将该scn号同步更新控制文件和数据文件头。在8i之后只有以下两种情况会发生完全检查点:
1、手工执行alter system checkpoint的命令;
2、数据库正常shutdown (immediate,transcational,normal)。
所谓增量检查点说白了,就是
1、CKPT每3秒一次的检查DBWn写进度并在控制文件中记录检查点位置(checkpoint position)和更新heartbeat信息
2、CKPT定期触发DBWn去写checkpoint queue中的脏数据
日志切换触发的是normal checkpoint,而不是大家所说的增量checkpoint,只不过log switch checkpoint的优先级非常低,当一个log switch checkpoint发生的时候它并不会立即的通知DBWn进程去写数据文件,但是当有其它原因导致checkpoint或者是写入数据文件的RBA超过log switch checkpoint的checkpoint RBA的时候,这次的log switch checkpoint将会被标记成完成状态,同时更新控制文件和数据文件头。
触发dbwr的条件不只是ckpt,所以ckpt必须要每个3秒去检查dbwn写进度,然后把检查点位置更新到控制文件。那么控制文件会认为在这个检查点位置之前的所有redo都已经体现到数据文件。在oracle正常运行时,你会发现发生的都是增量检查点进程,除非人为操作。而且在转储的数据文件头和控制文件的trace中,相关scn信息是不会变化的。
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 dis k rba是oracle前滚操作的终点。比这个更高的rba,都应该还驻留在log buffer中。还没有被LGWR写入日志文件。所以是不能被用于恢复的。
在DBWn写dirty buffer这个检查点过程中,Oracle也可以继续产生dirty buffer,DBWn也不是一次要把所有dirty buffer全部写到磁盘(不同于完全检查点的地方),这样就提高了检查点的效率,使得数据库要做恢复的时候从这个最新位置开始做恢复,而不是从数据文件 中的checkpoint scn(上一个完全检查点位置) 开始做恢复,这样将缩短恢复时间。
- 点赞
- 收藏
- 关注作者
评论(0)