oracle学习笔记 实例崩溃恢复原理剖析

Posted 新站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle学习笔记 实例崩溃恢复原理剖析相关的知识,希望对你有一定的参考价值。

oracle学习笔记 实例崩溃恢复原理剖析

上节讲了检查点队列的内容和工作方式,
这节课讲检查点队列有什么意义。

讲的知识叫oralce的实例崩溃恢复,
实际核心内容是检查点队列的作用。

一)功能

实例崩溃恢复是oracle的一个功能。

计算机中功能是实现编程目的的基本单位,
由一段或短或长的代码构成,
功能常常还会需要其它代码段或其它功能的支持。

人们之所以使用一个软件就是使用它的功能,
他可以达到使用者的目的,
而要构建一个功能则是程序员的工作。
功能使用时会因为程序的完善程度,造成不同的体验,

老师经常在课程中提到用户体验,都是由程序中功能实现的好坏造成的。

二)脏块和数据丢失

oracle有buffercache,
数据库正常运行期间,
buffercache里有很多的脏块。

脏块就是oracle在内存里面修改完了但是没有写到磁盘上。
也就是缓存的数据,
如果说服务器突然掉电了、突然死机了或者非正常关闭,
内存里的数据马上就没了。
这时很多的脏块会出现没有写到磁盘上出现数据丢失的情况。

数据丢失又分几种情况:
第一种情况不能丢失的,
第二种情况可以丢失的。

对oracle来讲未提交的事物所修改的数据块可以丢失,
已提交事务所对应的数据块所对应的脏块不能丢失。

这就是讲的丢失的两种情况。

脏块往回写的时候是DBWR做的事情。

第一种情况是一个脏块被修改的行对应的事务已经提交,
但是这个数据还没有写到磁盘上,
因为oracle提交的时候只是日志写到redolog,脏块可以不写回来,
脏块所对应的事务已经提交,这种脏块是不能丢失的。

第二种情况这个脏块所对应的事务还没有提交,
这种脏块可以丢失。

数据库崩溃的瞬间,
这两种脏块都会有,
对第一种脏块的丢失显然我们不能接受,
第二种脏块的丢失我们是可以接受的。

所以这里要明确一个概念,
oracle崩溃以后有些脏块需要找回来,
要通过日志找回来。

三)脏块和日志

再看日志,
一部分日志在logbuffer里面,
一部分日志在redolog里面。

数据库崩溃的瞬间buffercache里面有脏块。

第一种情况,
这个脏块所对应的日志已经写到磁盘上,就是已写到redolog。
另外一种情况,
这些脏块所对应的日志在logbuffer里面。

反过来这么说,
如果这个脏块所对应的日志还在logbuffer里面,
那说明这个日志所对应的事务肯定还没有提交,
如果这个脏块所对应的事务已经提交的话,
一定会写到磁盘上。

一个脏块被修改了,但是修改所对应的事务还没有提交,
同时这个脏块所对应的日志还在logbuffer里面,
这时数据库对于这个脏块是可以丢失的。
数据库崩溃以后日志丢失了,
这个日志丢失了这个脏块也丢失了,
可以认为我们对这个脏块所对应的修改从来没有发生过。

对另一个脏块来讲,
它修改了,它所对应的事务只要是提交了,
一定会写到磁盘上。
既然日志写到磁盘了,
我可以通过日志再把脏块再给构造出来 。

四)日志和数据丢失

oracle崩溃以后很多脏块丢失了。

oracle下次启动的时候,自动会发现数据库非正常关闭。
oracle发现非正常关闭以后,oracle会做一件事情,做实例崩溃恢复。
就是使用oracle磁盘上的日志redolog,
将数据库崩溃瞬间所对应的脏块构造出来。

如果数据库启动起来以后,
使用日志再把这个脏块构造出来,
也就是我把数据库buffercache恢复到出事的瞬间,
这样对数据库来讲没有丢失数据,是可以的。

当然oracle跑日志,使用日志恢复的时候,
只能恢复到磁盘上的最后一条日志,
对于logbuffer里面的日志它也丢了。
但是我们讲过,
logbuffer对应的这些脏块肯定没有提交,
丢了就丢了。

oracle数据库非正常关闭或者服务器死机等等原因,
导致oracle实例崩溃导致脏块丢失。
oralce数据库下次启动的时候,
oracle就可以使用redolog里面的日志将脏块构造出来。
将我们所需要的所有脏块构造出来,
不需要的脏块可以不构造出来。

五)实例崩溃恢复和日志

实例崩溃恢复的时候需要使用redolog里面的日志。

1)恢复的终点

redolog里有最新的日志,
使用日志使用到redolog里面的最后一条,
跑日志的时候把所有的日志跑完,把所有的日志都用完,
终点是最后写入的最新的一条。

比如数据库中有三组日志里面有好多日志,
可能有人有5组有10组日志。

我要把这些脏块给构造出来,
终点知道了,
是current日志的最后一条日志。

2)LRBA的位置

我们需要知道起点,
起点肯定在redolog里面。

回顾一下,
oracle崩溃的一瞬间有很多脏块,
使用检查点链起来。

我们看一下当前我们数据库的情况

SQL> select CPDRT,CPLRBA_SEQ||'.'||CPLRBA_BNO||'.'||CPLRBA_BOF "Low RBA",
CPODR_SEQ||'.'||CPODR_BNO||'.'||CPODR_BOF "On disk RBA",CPODS,CPODT,CPHBT
from x$kcccp;  2    3

     CPDRT Low RBA         On disk RBA     CPODS            CPODT                     CPHBT
---------- --------------- --------------- ---------------- -------------------- ----------
       355 5.31404.0       5.33937.0       534061           04/19/2017 08:33:25   911688533
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0

8 rows selected.

有Low RBA 和On disk RBA。

检查点队列里最早脏的块对应的地址,
在redolog中的一个位置。
redolog都在磁盘上,
redolog中的最后一条日志是最新的日志on disk RBA 。
对应LRBA的日志记录对应检查点队列中的第一个脏块的第一条日志。

redolog中LRBA地址的此前的所有的日志所对应的块,
都已经写到磁盘了。
因为LRBA是最早脏所对应的日志,
在它之前的所有的日志它们对应的脏块对应的块,
已经写到磁盘了。

在LRBA地址后面的日志记录,
对应着当前系统中的脏块。

3)起点

比如现在要把原buffercache里面的几个脏块构造出来。
如前数个脏块对应着redolog中的LRBA地址后面的一段redo记录的地址,
而检查点队列中最后面的脏块的redo记录对应在logbuffer中的一部分地址。

比如前三个脏块,
对应着redolog中的LRBA地址后面的一段redo记录的地址或几条redolog记录地址,
而检查点队列中最后面的脏块如第四个脏块的redo日志redo记录对应在logbuffer中的一部分地址,
数据库在这个瞬间是这个情况。

CKPT这个进程运行的时候,
把起点就是LRBA记录到控制文件中了。

数据库突然崩了,
崩了以后logbuffer丢了,
四个脏块也丢了。

oracle下次启动起来以后,
在控制文件中找到LRBA地址,
因为redolog中LRBA后的redo log记录还在日志里面。

根据控制文件记录的LRBA地址可以找到redolog中的起点,
然后使用日志、应用日志,
就可以把原检查点队列的前三个块构造出来。

第四个块构造不出来,
一定说明一个问题,第四个块所对应的事务一定没有提交。
我们就认为从来没有发生过,
就是第四个块不需要构造出来。

我们把前三个块构造出来了,
这时候oracle没有出现数据丢失,
我们只要保证所有已提交事务所对应的修改能够构造出来就OK了。

所有已提交事务所对应的日志一定写到redolog里面去了,
而且用redolog一定可以把需要的脏块构造出来。

4)回滚

但是同时也有可能把没有必要构造出来的脏块也构造出来,
而且一定会出现。

比如一个块它所对应的事务没有提交,
后面有个块对应的事务已经提交了。
但是构造的时候,
日志是按照顺序跑的,
为了构造后面已提交事务的块,
把前面未提交事务的块也构造出来了。

也就是说oracle实例崩溃恢复的时候,
确定起点确定终点以后跑日志,
结果把已提交的事务肯定都构造出来了,
同时未提交事务也有部分被构造出来了,
但是保证了没有数据丢失。

对于未提交事务构造出来了,
oracle都会对所有未提交事务回滚。

哪些事务未提交需要回滚这是以后讲undo时要讲的内容。

5)前滚和回滚

首先oracle发现数据库非正常关闭需要做实例恢复。
第二oracle在控制文件中找到检查点队列的LRBA地址,根据LRBA找到日志中的起点,
然后从日志起点跑一直跑到日志的终点。
终点就是redolog里面的current中的最后一条日志,
跑到最后以后我们保证oracle所有已提交事务所对应的脏块都被构造出来了。
但同时一些没有提交事务的所对应的脏块也被构造出来了,
没关系,那些未提交事务oracle在undo里面已经记录了,
oracle在此后的操作中会自动的将崩溃前未提交事务自动进行回滚。
这件事oracle会自动去做。

前滚就是我讲的实例崩溃恢复,
找起点确定终点跑日志,
跑日志这个过程叫前滚,把脏块构造出来了。
构造出来以后还有一些块是脏块被构造出来了但是它的事务没有提交,
没关系oracle此后会慢慢去回滚。
所以说有前滚有回滚,
这就是oracle实例崩溃恢复。

六)检查点队列和恢复的关系

检查点队列这个技术其实就是来确定日志的起点,
就这么个作用。

oracle8以前它是没有检查点队列的,
它根本不把这些脏块使用检查点队列串起来。

那个时候oracle崩溃以后要实例恢复的时候,
也就是确定不了起点。
他就应用redolog里面所有的日志,
当然这个所有可以打引号,
并不是所有但几乎是所有。

应用日志多了没关系,
就怕它应用的少了,
应用的多了可以回滚。

在没有检查点队列以前,
就是在oracle8以前,
oracle崩溃恢复的时候要跑非常多的日志。
oracle启动的时候速度就会变慢,
所以检查点队列加快了oracle实例崩溃恢复。

没有检查点队列oralce实例崩溃恢复的时候跑的日志会很多,
打开速度会慢。
如果有检查点队列,
oracle启动的时候,
oracle实例崩溃恢复的时候启动速度会变快。
就这么一个作用。

实例崩溃恢复知识点后面还会慢慢的往里深入加一些量,
我们不可能一次性到位的把所有东西都讲的很细很明白,
要一步步去深入一步步去讲。

2017年5月5日
文字:韵筝

以上是关于oracle学习笔记 实例崩溃恢复原理剖析的主要内容,如果未能解决你的问题,请参考以下文章

TRUNCATE TABLE恢复系列一:深层剖析内部原理

Oracle学习笔记 深入剖析事务槽及Oracle多种提交方式

Oracle 学习笔记 图解深入剖析一个事务的操作流程

oracle学习笔记 锁基础原理

oracle学习笔记 锁基础原理

go语言学习笔记 — 基础 — 函数(12):防止程序崩溃—— 宕机恢复(recover)