dbwn和checkpoint之间怎么协调工作的?

先看几个概念吧。

一、buffercache中的链

数据库实例有buffercache, buffercache里面有很多buffer。

buffercache里面单独有一块内存区域用来记录, 有很多链是chain。

如: LRU链least recent use最近最少使用,LRU上链的是干净块。

LRUW链Least Recently Used Write,也叫做dirty list,是脏数据块链表。

LRU链是将干净块将可用块给它串起来, 将来到从buffercache里面找可用块的时候就找LRU链。

同样的LRUW它链的是脏块给链起来, 将来我DBWR要将脏块写到磁盘上的时候就访问LRUW这个链。

我们之所以把块链起来, 就是为了组织和管理这些块, 为了将来从这个链上找相应的块。

不同的链有不同的功能。

oracle buffercache里面还有一种链叫检查点队列链, checkpoint query链。 首先来讲它是个链一根链, 这个链上链的是buffer,链的是块。

LRU链的是干净的, 按照数据块访问的频率, 也就是说分数据块的冷热来链的。

buffercache里面还有一个CBC链cache buffer chain , CBC是按照地址链起来的。

检查点队列这个链, 首先来讲它链起来的是脏块, 也就是说我们的脏块不仅仅挂在LRUW链上, 还挂在检查点队列这个链上。

脏块挂在LRUW上是按照这个块的访问频率冷热顺序挂的, 这个块是个脏块但是它不怎么经常被访问就挂在这个链的冷端, 这个块是脏块它经常被访问那么就挂在LRUW的热端, 冷端的脏块会被率先写入到磁盘上成为干净块, 因为它是脏块,但是它不怎么经常被访问, 这时候DBWR会优先把它写到磁盘上, 一旦写到磁盘上它就是干净块了,成了干净块了它就挂在LRU上, 就可以被重复使用被覆盖。

这也符合我们buffercache的一个使用原理, 不怎么使用的块我们可以把它冲刷掉, 经常被访问的块我们希望尽量长时间的缓存在cache里面, 所以有LRU和LRUW它有各自的用途。

检查点队列它链的是脏块, 它按照这个块第一次脏的时间链起来的。

假设我现在有四个脏块。

第一个脏块是十点零一分的时候脏的, 第二个脏块是零二, 第三个脏块是零三, 第四个脏块是零四分脏的。

第一次脏的时间分别是: 01分02分03分04分

在05分的时候, 第一个脏块又被脏了一次。 在06分的时候, 第二个脏块又被脏了。 在07分的时候, 第四个脏块又被脏了。 在08分的时候, 第三个脏块被脏了。 这有可能!

检查点队列这个队列是按照块第一次脏的时间给它挂起来的。

第一个块第一次脏是01分, 挂在最上面。 第二个脏块挂在第二个位置, 第三个脏块挂在第三个位置, 第四个脏块挂在第四个位置, 这四个脏块按照这个块第一次脏的时间点给挂在链上的。

在05分的时候, 比如举例讲一号块在05分的时候被脏了又被脏了一次, 这个时候05分比最下面的04分的时间要晚, 这个块也不会挂在04分的后面, 因为我们是按照它第一次脏的时间点挂起来的。

所以要先记住, 第一个检查点队列上面对应的块是脏块, 第二个它是按照这个脏块第一次脏的时间点挂起来的。

先理解先记住这两个点, 记住以后我们看。

LRUW是按照冷热将脏块链起来, 它主要指导DBWR按照冷热哪些该写哪些不该写。

二、RBA和检查点队列

检查点队列按照这种方式链起来的意义。

检查点队列上面链的是脏块, 按照第一次脏的时间点给串起来的一系列脏块。

1)脏块中的RBA

在链上有一系列的块按顺序挂在上面, 还有logbuffer,redolog。

讲几个东西, 一个叫RBA, 一个叫LRBA, 一个叫HRBA。

RBA是redo block address, 是日志的地址,日志块的地址叫RBA。

假设我们对一个数据块进行修改, 会产生日志, 日志有一个地址就是RBA地址。

修改一个数据块会产生一个日志, 就有一个地址,这个地址叫RBA地址, 我就在这个数据块里面记一下这个RBA地址。 将来这个块要恢复的时候, 它知道它的改变都有哪个地址, RBA就是日志地址。

先来看一下RBA的构成: 它由3部分组成,4byte+4byte+2byte,byte是指字节。 分别为 logfile sequence number ,logfile block number,byte offset into the block 。 即所在redo文件的序列号,所在日志文件中的块号,以及距离块开始位置的偏移量。 RBA也可以说是redo byte address。

对每个脏块来讲有LRBA和HRBA, LRBA就是这个脏块第一次被脏的地址的那个日志地址。 这个块第一次被脏的地址, 它对应着logbuffer日志中的一个地址, 这个数据块被脏了很多次, 被脏了第二次第三次第四次第五次被脏的时候, 假设最近一次是第五次被脏, 它也对应着一个地址叫HRBA地址。

也就是说LRBA和HRBA分别记录着, 这个数据块最早一次脏所对应的日志中的地址, 和最近一次脏所对应的日志中的地址。

这两个地址在日志中的中间的地址, 是描述了这个块的脏的过程。

所以说记住数据块里面有两个地址LRBA跟HRBA。

2)LRBA地址在检查点队列中的作用

这个时候我们反过来说, 检查点队列里面的数据块, 是按照第一次脏链起来的, 其实也可以这么来说, 它们是按照这个数据块的LRBA地址链起来的。

日志我们这么来描述更确切些。

我们不看logbuffer和redolog, 日志其实就是一行行的串起来的, 所有的日志都是这么串起来的, 日志就是一行行的。

检查点队列上每个数据块记录的LRBA, 是这个数据块第一次被脏的地址, 一个数据块的LRBA, 对应着日志中的一行的地址。

目前就是检查点队列的第一个脏块所对应的LRBA地址是日志中的其中一行, 检查点队列的所链的所有的脏块, 就是检查点队列的所有的脏块, 它们所对应的日志都在第一个脏块所对应的日志地址以下。

检查点队列将所有的脏块链起来, 第一个块是最早脏的, 它第一次脏的对应的日志是日志中的一行, 第一个块下面所有的脏块它们被脏的所对应的日志, 都在日志中的第一个脏块第一次脏的日志以下。

因为它是最早被脏的, 最早脏的日志在日志中的一个地方, 而日志是按照时间顺序记录着buffercache的变化历程, 也就是下面所有的日志, 也就是检查点队列的后面所有的数据块, 它们的脏所对应的日志, 都在那条日志的下面。

三、检查点进程和检查点

我们知道有一个CKPT进程叫检查点进程

执行命令

?
1
[root@redhat4 ~]# ps -ef|grep ora

结果中有一个进程

?
1
oracle    6628     1  0 13:15 ?        00:00:00 ora_ckpt_jiagulun

就是检查点进程

这个进程分两块有两种工作方式

第一种工作方式叫完全检查点

当完全检查点发生的时候, CKPT进程会触发DBWR, 将所有的脏块写到磁盘上这叫完全检查点。

第二种方式是增量检查点

是当增量检查点发生的时候, CKPT进程会将第一个脏块的第一个log地址, 将检查点队列的第一个脏块的所对应的LRBA地址, 将这个日志地址记录到控制文件中。

完全检查点发生, 最经典的是关闭数据库的时候。

这时oracle会发生一个完全检查点, 这时候CKPT会触发DBWR将所有的脏缓冲区写到磁盘上, 这样数据库是相对的干净的关闭了。

数据库正常运行的时候只有正常关闭的时候才会发生完全检查点, 所以一般数据库正常运行期间完全检查点几乎不发生, 它就会发生增量检查点。 oracle每隔3秒钟会发生一次增量检查点。

增量检查点发生的时候CKPT进程会将检查点队列的最早脏的数据块所对应的LRBA地址记录到控制文件中。 增量检查点是每隔三秒钟发生一次。

讲课有两种先告诉作用再剖析原理, 另外一种先剖析原理再告诉作用恍然大悟的感觉。

当增量检查点发生的时候它还会做一件事情, 它会检查到检查点队列, 如果他发现检查点队列上面链的这些脏块太多了, 同时它发现系统的IO不是很忙, 它会结合这两个因素去触发DBWR去缩短检查点队列, 缩短检查点队列就是将队列的上半部分一些脏块写到磁盘上。

DBWR写的时候有两种情况, 第一种情况 根据LRUW链根据冷热去写; 第二种情况 如果说check point query检查点队列太长了以后, 检查点队列checkpoint进程触发的时候也会适当的触发DBWR去将检查点队列最早脏的哪些块。 队列上的一系列块,部分的写到磁盘上, 这时候检查点队列就缩短了。

这是增量检查点会做的两件事情, 增量检查点主要做的事情是记录检查点队列最早脏的块对应的LRBA地址。

四、on disk rba

还有一个 on disk rba

我们执行一个sql语句查一下

?
1
2
3
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;

执行结果

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
---------- -------------------- -------------------- ---------------- -------------------- ----------
         87 5.21988.0            5.22444.0            527629           04/18/2017 13:58:38   911687624
          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.

CPDRT列是检查点队列中的脏块数目; CPODS列是on disk rba的scn ; CPODT列是on disk rba的时间戳 ; CPHBT列是心跳。

其中CPDRT列是检查点队列中脏块的数目, 就是目前我的buffercache里面有87个脏块。 Low RBA列是LRBA地址是检查点队列中最早脏的块的最早的日志地址。

On disk RBA列是一个地址

我们知道日志在logbuffer里面有, redolog里面也有。

logbuffer里面记录着很多日志, 现在redolog中的一个日志状态是current就是最新的。

然后logbuffer有个LGWR进程, 它每隔三秒钟会把logbuffer中的日志写到redolog中的状态是current的日志文件中。 或者commit的时候往redolog中写, 总之LGWR会频繁的将logbuffer中的日志写到current里面去。

我们把current日志拿出来, on disk rba是current日志的最后一条日志的地址。 就是我们目前数据库里面的所保存的最后一条日志的地址, logbuffer里面的很多日志还没有写到current里面去, 但是logbuffer里面写进来的最后一条日志叫on disk rba。

目前数据库里面的current redolog里面的所记录的最新的rba地址叫on disk rba。

On disk RBA比Low RBA更新一些, Low RBA在On disk RBA的后面。

目前数据库所产生的日志, 全部用串行的方式表示出来, 最新的一些在buffer里面, 较早的一些在redolog里面。

地址从redolog到logbuffer里面是越来越新, 在redolog中的最后一条地址就是on disk rba, 因为它是目前redolog里面最新的, 就是on disk rba是最新的。

上面就是查询结果中的5.22444.0地址为On disk RBA。

检查点队列中第一个脏块的最早的一个redo地址, 是比on disk rba在redolog中更早的一个地址, 我们的这个系统里面最早脏这个块对应的日志已经写到redolog里面去了。 这是我们实际的这个情况。

从结果看

?
1
2
3
      CPDRT Low RBA              On disk RBA          CPODS            CPODT                     CPHBT
---------- -------------------- -------------------- ---------------- -------------------- ----------
         87 5.21988.0            5.22444.0            527629           04/18/2017 13:58:38   911687624

目前有87个脏块

我们现在执行一条命令

?
1
alter system flush buffer_cache

将所有的脏块给清到磁盘上

?
1
2
3
SQL> alter system flush buffer_cache;
 
System altered.

然后再查一下rba

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
---------- -------------------- -------------------- ---------------- -------------------- ----------
          0 4294967295.429496729 5.30959.0            533161           04/18/2017 14:32:48   911688308
            5.65535
 
          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.

我们发现CPDRT的值就是脏块的数量为0了, 因为刚才已经把所有的脏块给清过来了。

清完了以后, CPDRT为零说明脏块没了,检查点队列为空了。 Low RBA的值是4294967295.4294967295.65535也就是是无穷大了就是空了。 4294967295是4个字节数字所表示的最大值, 65535是2个字节数字所表示的最大的值。 这时LRBA的值的三节 4字节+4字节+2字节, 每节中的每个字节中的每一位都被填充了1, 得到它能表示的最大的值用来表示无穷大。

参考链接:http://blog.csdn.net/cymm_liu/article/details/7337020


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值