暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Oracle控制文件与数据库初始化——常规检查点与增量检查点

原创 eygle 2020-01-02
1489

常规检查点与增量检查点

为了理解常规检查点和增量检查点的概念,首先需要介绍一下脏缓冲列表(LRUW List)。前面提到,当数据在Buffer Cache中被修改之后,Dirty Buffer会被转移到LRUW List,以便将来执行的检查点可以将这些修改过的Buffer写出到数据文件上。

但是注意,由于LRUW List上的Buffer并没有严格顺序,有的Buffer反复被修改,在写出之前,可能会被从LRUW移动回AUXILIARY lru list,当这样的Dirty Buffer再次回到LRUW列表时,会倍添加到链表尾部,也就是说一个Buffer在LRUW链表上的位置可能发生变化,所以当检查点发生时,Oracle需要将脏缓冲列表上的数据全部写出到数据文件。

为了区分,在Oracle8之前,Oracle实施的这类检查点通常被称为常规检查点(Conventional Checkpoint),由于检查点时需要写出全部的脏数据,所以也被称为完全检查点(Complete Checkpoint)。

常规检查点按特定的条件触发(log_checkpoint_interval,log_checkpoint_timeout参数设置及log switch等条件触发),触发时会同时更新数据文件头以及控制文件记录检查点信息。

从Oracle8开始,Oracle演进了新的算法,进而引入了增量检查点(Incremental Checkpoint)的概念。
和以前的版本相比,在新版本中,主要的变化是引入了检查点队列(Buffer Checkpoint Queue - CKPTQ)机制。在数据库内部,每一个脏数据块都会被记录到检查点队列,按照LRBA(Low RBA - 第一次对此数据块修改对应的Redo Byte Address)的顺序来排列,如果一个数据块进行过多次修改,该数据块在检查点队列上的顺序并不会发生变化(相对于LRBA,后面修改的RBA被称为HRBA)。

检查点队列的内存存储空间在Shared Pool内存中分配:

SQL> select * from v$sgastat where upper(name) like '%CHECKPOINT%';
POOL          NAME                            BYTES
------------  -------------------------- ----------
shared pool Checkpoint queue         410624
shared pool   log_checkpoint_timeout        12360
复制

当执行增量检查点时,DBWR从检查点队列按照Low RBA的顺序写出,此时先修改的数据就可以被按顺序优先写出,实例检查点因此可以不断增进,阶段性的,CKPT进程使用非常轻量级的控制文件更新协议,将当前的最低RBA(也即Low Cache RBA)写入控制文件,为了减少频繁增量检查点的性能影响,CKPT在进行轻量级更新时,并不会改写控制文件中数据文件的检查点信息以及数据文件头信息,而只是记录控制文件检查点SCN(Controlfile Checkpointed at scn)并且根据增量检查点的写出增进RBA信息,同时不需要更改数据文件头信息。

通过增量检查点,数据库可以将以前的全量写出变更为增量渐进写出,从而可以极大的减少对于数据库性能的影响;而检查点队列则进一步的将RBA和检查点关联起来,从而可以通过检查点来确定恢复的起点

增量检查点的进度可以通过X$KCBBES表来查询,该表的含义为:

	X$KCBBES—
           [K]ernel [C]ache [B]uffer Management Buffer Event Statistics
复制

该视图记录了内存中Buffer的写出统计,其中INDX为 4的条目即增量检查点写出的Buffer数量:

SQL> desc x$kcbbes
 Name					   Null?    	Type
 ----------------------------- -------- ----------------------------
 ADDR						    		RAW(8)
 INDX						    		NUMBER
 INST_ID					    NUMBER
 REASON 					    NUMBER
 PRIORITY					    NUMBER
 SAVECODE					    NUMBER

SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production

SQL> select * from x$kcbbes where reason >0;

ADDR		       INDX    INST_ID	   REASON  PRIORITY   SAVECODE
---------------- ----- ---------- --------- ---------- ----------
00002B37AA4429E8	  2	     1	      480	 199	     71
00002B37AA4429E8	  4	     1	      199	   0	      7
00002B37AA4429E8	  9	     1		   6	   0	      0
00002B37AA4429E8	 11	     1	   784125	   0	      0
00002B37AA4429E8	 12	     1	      284	   0	      0
复制

反复查询该视图可以观察增量检查点的进度,如果REASON值增加则意味着检查点在增进,如果不变,则意味着检查点未发生(注意,即便是增量检查点其发生也可能间隔较长时间)。

SQL> select * from x$kcbbes where indx=4; 
ADDR		       INDX    INST_ID	   REASON   PRIORITY   SAVECODE
---------------- ---------- ---------- ---------- ---------- ----------
00002AC45797C2F8	  4	     1	     5884	   0	      7
SQL> select * from x$kcbbes where indx=4; 
ADDR		       INDX    INST_ID	   REASON   PRIORITY   SAVECODE
---------------- ---------- ---------- ---------- ---------- ----------
00002AC4579578A0	  4	     1	     5893	   0	      7
复制

检查点队列在数据库内部通过Latch保护:

SQL> select name,gets,misses from v$latch where name='checkpoint queue latch';
NAME                                                GETS     MISSES
------------------------------------ ---------- ----------
checkpoint queue latch                     14710851          0
复制

Checkpoint Queue Latch存在多个子Latch,可以通过V$LATCH_CHILDREN视图查询:

SQL> select name,gets,misses from v$latch_children where name='checkpoint queue latch';
NAME                                           GETS     MISSES
---------------------------------------- ---------- ----------
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       917660          0
checkpoint queue latch                       924547          0
checkpoint queue latch                       927484          0
checkpoint queue latch                       920711          0
checkpoint queue latch                       920711          0
checkpoint queue latch                       920711          0
checkpoint queue latch                       920711          0
复制

除了检查点队列(CKPTQ)之外,数据库中还存在另外一个队列和检查点相关,这就是文件检查点队列-FILE QUEUE,通常缩写为FILEQ,文件检查点队列的引入提高了表空间检查点(Tablespace Checkpoint)的性能。

每个Dirty Buffer同时链接到这两个队列, CKPTQ包含实例所有需要执行检查点的Buffer,FILEQ包含属于特定文件需要执行检查点的Buffer,每个文件都包含一个文件队列,在执行表空间检查点请求时需要使用FILEQ,通常当对表空间执行Offline等操作时会触发表空间检查点。

在Buffer Chache中,每个Buffer的Header上都存在CKPTQ以及FILEQ队列信息,通过如下命令可以转储Buffer Cache信息(注意应当仅在测试环境中尝试):

alter session set events 'immediate trace name buffers level 10';
复制

以下BH信息来自Oracle9i 9.2.0.4数据库环境:

    BH (0x0x55fba950) file#: 2 rdba: 0x0080008c (2/140) class 34 ba: 0x0x553d8000
      set: 3 dbwrid: 0 obj: -1 objn: 0
      hash: [54ee90b0,57476608] lru: [55fbaa54,55fba8dc]
      LRU flags:
      ckptq: [55feb234,55ffce68] fileq: [55ffcf2c,55ffce70]
      st: XCURRENT md: NULL rsop: 0x(nil) tch: 31
      flags: buffer_dirty gotten_in_current_mode block_written_once
              redo_since_read
      LRBA: [0x1d.38e.0] HSCN: [0x081b.dc808434] HSUB: [1] RRBA: [0x0.0.0]
      buffer tsn: 1 rdba: 0x0080008c (2/140)
      scn: 0x081b.dc808434 seq: 0x01 flg: 0x00 tail: 0x84340201
      frmt: 0x02 chkval: 0x0000 type: 0x02=KTU UNDO BLOCK
复制

注意摘录信息中的CKPTQ和FILEQ,这就是检查点队列和文件队列。每个队列后面记录了两个地址信息,分别是前一块以及下一块的地址,通过这个信息CKPTQ和FILEQ构成了双向链表。注意仅Dirty Buffer才会包含CKPTQ信息,否则为NULL,信息类似:ckptq: [NULL] fileq: [NULL]。

同样对上一个跟踪文件进行grep信息输出,来看一下这两个队列:

[oracle@jumper udump]$ grep ckptq eygle_ora_1467.trc |grep -v NULL
      ckptq: [55fba708,56374c18] fileq: [55fba710,56374c70]
      ckptq: [55ffccf0,55ffd504] fileq: [55ffccf8,55ffd50c]
      ckptq: [55fbaab4,55fba880] fileq: [55fbaabc,55fba888]
      ckptq: [55fba880,55fba7c4] fileq: [55fba888,55fba7cc]
      ckptq: [55ffd09c,55ffcfe0] fileq: [55ffd0a4,55ffcfe8]
      ckptq: [55fba64c,55feb234] fileq: [55fba654,55fbaa00]
      ckptq: [55feb3ac,55ffcf24] fileq: [574d0c08,55ffcf2c]
      ckptq: [55fba9f8,574d0bb0] fileq: [55fbaa00,574d0c08]
      ckptq: [55feb234,55ffce68] fileq: [55ffcf2c,55ffce70]
      ckptq: [55fba7c4,55fba708] fileq: [55fba7cc,55fba710]
      ckptq: [56374c18,55ffd09c] fileq: [56374c70,55ffd0a4]
      ckptq: [55ffcfe0,55ffccf0] fileq: [55ffcfe8,55ffccf8]
      ckptq: [55ffcf24,55fba9f8] fileq: [55feb3b4,574d0bdc]
      ckptq: [574d0bb0,55fba64c] fileq: [574d0bdc,55feb23c]
复制

简单整理一下CKPTQ,其顺序就是(对于):

55fbaab4->55fba880->55fba7c4->55fba708->56374c18->55ffd09c->55ffcfe0->55ffccf0->55ffd504
55feb3ac->55ffcf24->55fba9f8->574d0bb0->55fba64c->55feb234->55ffce68
复制

在SGA中存在一块内存区域用于记录这个检查点队列:

SQL> select name,bytes from v$sgastat where upper(name) like '%CHECKPOINT%';
NAME                                          BYTES
---------------------------------------- ----------
Checkpoint queue                             282304
复制

从Oracle10g开始,数据库中额外增加了对象检查点队列(Object Queue - OBJQ)用于记录对象检查点信息:

    BH (0x273f092c) file#: 1 rdba: 0x00401009 (1/4105) class: 1 ba: 0x271ec000
      set: 6 blksize: 8192 bsi: 0 set-flg: 2 pwbcnt: 133
      dbwrid: 0 obj: 517 objn: 517 tsn: 0 afn: 1
      hash: [5ebae9b8,5ebae9b8] lru: [273f0a30,273f08d0]
      lru-flags:
      ckptq: [243ea704,277f0c14] fileq: [5e4b08d4,277f0c1c] objq: [277f0c94,273f0874]
      st: XCURRENT md: NULL tch: 2
      flags: buffer_dirty gotten_in_current_mode block_written_once
              redo_since_read
      LRBA: [0x38.11a97.0] HSCN: [0x81b.8f844f3e] HSUB: [1]
      buffer tsn: 0 rdba: 0x00401009 (1/4105)
      scn: 0x081b.8f844f3e seq: 0x01 flg: 0x02 tail: 0x4f3e0601
      frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
复制

下图是Buffer Header的结构示意图,对照以上Buffer Header转储信息可以更加清晰的了解BH的结构:

image.png

共享池中分配了相关内存用于OBJECT QUEUE:

SQL> select * from v$sgastat where name like 'object queue%';
POOL         NAME                            BYTES
------------ -------------------------- ----------
shared pool  object queue hash table d        6080
shared pool  object queue hash buckets      139264
shared pool  object queue                    49056
复制

了解了几种队列之后,下面让我们来看一下控制文件以及增量检查点的协同工作。以下输出来自Oracle 11g测试环境,两次Level 8级控制文件转储,时间间隔有8分钟左右(去除了一点次要信息)。

第一部分重要信息是控制文件的Seq号,控制文件随着数据库的变化而增进版本:

[oracle@localhost trace]$ diff 11gtest_ora_24951.trc 11gtest_ora_25106.trc
< DUMP OF CONTROL FILES, Seq # 1781 = 0x6f5
---
> DUMP OF CONTROL FILES, Seq # 1782 = 0x6f6
42c28
<       Control Seq=1781=0x6f5, File size=594=0x252
---
>       Control Seq=1782=0x6f6, File size=594=0x252
复制

接下来是控制文件检查点SCN,增量检查点不断增进的内容之一:

85c71
<  Controlfile Checkpointed at scn:  0x0000.00095a4c 07/07/2008 11:27:56
---
>  Controlfile Checkpointed at scn:  0x0000.00095ae6 07/07/2008 11:33:46
复制

检查点记录之后是RBA信息,检查点和Redo相关联在这里实现,通过以下信息可以注意到,通过增量检查点之后,Dirty Buffer数量从47降低到7,而Low Cache RBA从0x1d.4b1.0增进到0x1d.518.0,LOW Cache RBA是下一次恢复的起点,而On Disk RBA则是指已经写入磁盘(Redo Log File)的RBA地址,这是前滚恢复能够到达的终点,增量检查点的作用由此体现:

114,116c100,102
< THREAD #1 - status:0x2 flags:0x0 dirty:47
< low cache rba:(0x1d.4b1.0) on disk rba:(0x1d.515.0)
< on disk scn: 0x0000.00095a78 07/07/2008 11:28:18
---
> THREAD #1 - status:0x2 flags:0x0 dirty:7
> low cache rba:(0x1d.518.0) on disk rba:(0x1d.525.0)
> on disk scn: 0x0000.00095ada 07/07/2008 11:33:07
复制

最后一部分是Heartbeat心跳信息,每3秒更新一次用于验证实例的存活性,第一章中已经有所提及:

118c104
< heartbeat: 659472703 mount id: 1478358445
---
> heartbeat: 659472842 mount id: 1478358445
复制

通过以上分析可以清晰的看到增量检查点的实施过程,因为增量检查点可以连续的进行,所以检查点RBA可以比常规检查点更接近数据库的最后状态,从而在数据库的实例恢复中可以极大的减少恢复时间。

而且,通过增量检查点,DBWR可以持续进行写出,从而避免了常规检查点出发的峰值写入对于I/O的过度争用,通过下图可以清楚的看到这一改进的意义:

image.png

显而易见的是,增量检查点明显优于常规的完全检查点,所以在引入检查点队列之后,数据库正常情况下执行的都是增量检查点,从Oracle8i开始,完全检查点仅在以下两种情况下出现:

  • ALTER SYSTEM CHECKPOINT
  • SHUTDOWN (除ABORT方式外)

LOG SWITCH事件同样触发的是增量检查点,但是在LOG SWITCH触发的检查点会促使数据文件头与控制文件信息的同步(数据文件头的写操作并非每次Log Switch检查点都会发生)。

如前所述,我们知道每个Buffer都可能和ckptq、fileq、objq相关联,从而检查点也就有了不同的分类,常见的分类有:Full Checkpoint、Thread Checkpoint、File Checkpoint、Object Checkpoint、Parallel Query Checkpoint、Incremental Checkpoint、Log Switch Checkpoint.

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论