oracle checkpoint檢查點

eric0435發表於2013-01-20
檢查點
檢查點只是一個資料庫事件,它存在的根本意義在於減少崩潰恢復(crash recovery)時間.檢查點事件由ckpt後臺程式觸發,當檢查點發生時,ckpt程式會負責通知dbwr程式將髒資料(dirty buffer)寫出到資料檔案上,ckpt程式的另外一個職責是負責更新資料檔案頭及控制檔案上的檢查點資訊.

檢查點(checkpoint)的工作原理
在oracle資料庫中,當進行資料修改時,需要首先將資料讀入記憶體中(buffer cache),修改資料的同時,oracle會記錄重做(redo)資訊用於恢復.因為有了重做資訊的存在,oracle不需要在事務提交時(commit)立即將變化的資料寫回磁碟(立即寫的效率會很低),重做的存在也正是為了在資料庫崩潰之後,資料可以恢復.

常見的情況,資料庫可能因為斷電而crash,那麼記憶體中修改過的,尚沒有寫入資料檔案的資料將會丟失.在下一次資料庫啟動之後,oracle可以透過重做(redo)日誌進行事務重演(也就是進行前滾),將資料庫恢復到崩潰之前的狀態,然後資料庫可以開啟提供使用之後oracle可以將沒有提交的事務進行回滾.

檢查點的存在就是為了縮短這個恢復時間.當檢查點發生時(此時的scn被稱為checkpoint scn). oracle會通知dbwr程式,把修改過的資料,也就是此checkpoint scn之前的髒資料(dirty data)從buffer cache寫入磁碟,當寫入完成之後,ckpt程式則會相應更新控制檔案和資料檔案頭,記錄檢查點資訊,標識變更.

checkpoint scn可以從資料庫中查詢得到:
SQL> select file#,checkpoint_change#,to_char(checkpoint_time,'yyyy-mm-dd hh24:mi:ss') checkpoint_time from v$datafile;

     FILE# CHECKPOINT_CHANGE# CHECKPOINT_TIME
---------- ------------------ -------------------
         1            1131856 2013-01-18 01:33:36
         2            1131856 2013-01-18 01:33:36
         3            1131856 2013-01-18 01:33:36
         4            1131856 2013-01-18 01:33:36
         5            1131856 2013-01-18 01:33:36
         6            1131856 2013-01-18 01:33:36

6 rows selected.

SQL> select dbid,checkpoint_change# from v$database;

      DBID CHECKPOINT_CHANGE#
---------- ------------------
3172629284            1131856

在檢查點完成之後,此檢查點之前修改過的資料都已經寫回磁碟,重做日誌檔案中的相應重做記錄對於崩潰/例項恢復不再有用.

如果檢查點的頻率高,那麼恢復時間需要應用的重做日誌就相對得少,恢復時間就可以縮短,如果oracle可以在效能允許的情況下,使得檢查點的scn接賓redo的最新變更,那麼,使得oracle可以最大化地減少恢復時間.

常規檢查點與增量檢查點
髒緩衝列表(Dirty List).
當資料在buffer cache中被修改之後,Dirty Buffer會被轉移到dirty list,以便將來
執行的檢查點可以將這些修改過的buffer寫出到資料檔案上.

但是注意,由於dirty list上的buffer並沒有順序,有的buffer反覆被修改,在連結串列上的位置就可能發生變化,當檢查點發生時,oracle需要將髒緩衝列表上的資料全部寫出到資料檔案.為了區分,在oracle8之前,oracle實施的這類檢查點通常被稱為常規檢查點(Conventional checkpoint),由於檢查點時需要寫出全部的髒資料,所以也被稱為完全檢查點(complete checkpoint),常規檢查點按特定的條件觸(log_checkpoint_interval,
log_checkpoint_timeout引數設定及log switch等條件觸發),觸發時會同時更新資料檔案頭以及控制檔案記錄檢查點資訊.

從oracle8開始,oracle引入了增量檢查點(Incremental checkpoint)的概念.和以前的
版本相比,在新版本中,主要的變化是引入了檢查點佇列(checkpoint queue ckptq)機制.在資料庫內部,每一個髒資料塊都會被記錄到檢查點佇列中,按照LRBA(Low RBA,第一次對此資料塊修改所對應的redo byte address)的順序來排列,如果一個資料塊進行過多次修改,該資料塊在檢查點佇列上的順序並不會發生變化(相對LRBA,
後面修改的RBA被稱為HRBA)

當執行增量檢查點時,dbwr從檢查點佇列按照Low RBA的順序寫出,此時先修改的資料就可以被按順序優先寫出,例項檢查點因此可以不斷增進,同時,ckpt程式也階段性地使用非常輕量級的控制檔案更新協議,將當前的最低的RBA寫控制檔案.為了減少頻繁增量檢查點的效能影響,ckpt在進行輕量級更新時,並不會改寫控制檔案中資料檔案
的檢查點資訊以及資料檔案頭資訊.而只是記錄控制檔案檢查點scn(controlfile checkpoint at scn)並且根據增量檢查點的寫出增進RBA資訊.

透過增量檢查點,資料庫可以將以前的全量寫出變更為增量漸進寫出,從而可以極大工減少對於資料庫效能的影響;而檢查點佇列則進一步地將RBA和檢查點關聯起來,從而可以透過檢查點來確定恢復的起點.

檢查點佇列在資料庫內部透過latch保護:
select name,gets,misses from v$latch where name='checkpoint queue latch';

SQL> select name,gets,misses from v$latch where name='checkpoint queue latch';

NAME                                                     GETS     MISSES
-------------------------------------------------- ---------- ----------
checkpoint queue latch                                  86382          0

checkpoint queue latch存在多個子latch,可以透過v$latch_children檢視查詢:
select name,gets,misses from v$latch_children where name='checkpoint queue latch';

SQL> select name,gets,misses from v$latch_children where name='checkpoint queue latch';

NAME                                                     GETS     MISSES
-------------------------------------------------- ---------- ----------
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                  11374          0
checkpoint queue latch                                  11724          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0
checkpoint queue latch                                   4550          0

16 rows selected.

除了檢查點佇列(ckptq)之外,資料庫中還存在另外一個佇列和檢查點相關,這就是檔案檢查點佇列(file queue),通常縮寫為fileq,檔案檢查點佇列的引入提高了表空間檢查點(tablespace checkpoint)的效能.每個dirty buffer同時連結到這兩個佇列,ckptq包含例項所有需要執行檢查點的buffer,fileq包含屬於特定檔案需要執行檢查點的buffer,每個檔案都包含一個檔案佇列,在執行表空間檢查點請求時需要使用fileq,通常當對錶空間執行offline等操作時會觸發表空間檢查點.

在buffer cache中,每個buffer的header上都存在ckptq以及fileq佇列資訊,透過如下命令可以轉儲buffer cache資訊(注意應發僅在測試環境中嘗試);
alter session set events 'immediate trace name buffers level 10';

SQL> alter session set events 'immediate trace name buffers level 10';

Session altered.

SQL> select
  2  d.value||'/'||lower(rtrim(i.instance,
  3  chr(0)))||'_ora_'||p.spid||'.trc' trace_file_name
  4  from ( select p.spid
  5  from v$mystat m,
  6  v$session s,v$process p
  7  where m.statistic# = 1 and s.sid = m.sid and p.addr = s.paddr) p,
  8  ( select t.instance from v$thread  t,v$parameter v
  9  where v.name = 'thread' and
 10  (v.value = 0 or t.thread# = to_number(v.value))) i,
 11  ( select value from v$parameter
 12  where name = 'user_dump_dest') d
 13  /

TRACE_FILE_NAME
--------------------------------------------------------------------------------
/u01/app/oracle/admin/jingyong/udump/jingyong_ora_4239.trc


以下bh資訊來自oracle10g

    BH (0x24ff61dc) file#: 3 rdba: 0x00c00a6c (3/2668) class: 1 ba: 0x24eee000
      set: 3 blksize: 8192 bsi: 0 set-flg: 2 pwbcnt: 46
      dbwrid: 0 obj: 8780 objn: 8780 tsn: 2 afn: 3
      hash: [29115d3c,29115d3c] lru: [24ff62e0,24ff60d0]
      lru-flags:
      ckptq: [24ff5184,29150a60] fileq: [24ff518c,29150a9c] objq: [27b37888,27b37888]
      st: XCURRENT md: NULL tch: 35
      flags: buffer_dirty gotten_in_current_mode block_written_once
              redo_since_read
      LRBA: [0x5.2e7.0] HSCN: [0x0.11546d] HSUB: [1]
      buffer tsn: 2 rdba: 0x00c00a6c (3/2668)
      scn: 0x0000.0011546d seq: 0x01 flg: 0x02 tail: 0x546d0601
      frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

注意資訊中的ckptq和fileq,這就是檢查點佇列和檔案佇列,每個佇列後面記錄了兩個地址資訊,分別是前一塊以及下一塊的地址,透過這個資訊ckptq和fileq構成了雙向連結串列.注意僅僅只有dirty buffer才會包含ckptq資訊,否則為null,資訊類似如下
    BH (0x24be637c) file#: 1 rdba: 0x004096b0 (1/38576) class: 1 ba: 0x2480a000
      set: 3 blksize: 8192 bsi: 0 set-flg: 2 pwbcnt: 46
      dbwrid: 0 obj: 18 objn: 18 tsn: 0 afn: 1
      hash: [290c0878,290c0878] lru: [24be6320,24be6480]
      lru-flags: moved_to_tail
      ckptq: [NULL] fileq: [NULL] objq: [24be6374,24be64d4]
      st: XCURRENT md: NULL tch: 3
      flags: only_sequential_access
      LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]
      buffer tsn: 0 rdba: 0x004096b0 (1/38576)
      scn: 0x0000.00030101 seq: 0x01 flg: 0x04 tail: 0x01010601
      frmt: 0x02 chkval: 0x8c8d type: 0x06=trans data

[oracle@jingyong udump]$ grep ckptq jingyong_ora_4239.trc |grep -v NULL
      ckptq: [26c13b04,233f6364] fileq: [237e9e1c,237e9d6c] objq: [237e9de4,237ea0a4]
      ckptq: [233f6414,237e6be4] fileq: [233f641c,237e6bec] objq: [237e6c64,233f6494]
      ckptq: [237e9aa4,237e9cb4] fileq: [237e9aac,237e9cbc] objq: [237e9d34,27b8afa8]
      ckptq: [237e6c94,233f6154] fileq: [237e6c9c,233f615c] objq: [233f61d4,237e6d14]
      ckptq: [237e9944,237ea0d4] fileq: [237e994c,237ea0dc] objq: [237ea154,237e99c4]
      ckptq: [29150a60,237e9944] fileq: [29150a74,237e994c] objq: [27b1cc58,27b1cc58]
      ckptq: [26c13b04,26c18194] fileq: [26c13b0c,26c1819c] objq: [26c18214,26c13b84]
      ckptq: [26c12924,291529c8] fileq: [26c1292c,29152a40] objq: [27b1d0b8,26c129a4]
      ckptq: [26c18034,26c12874] fileq: [26c1803c,26c1287c] objq: [26c128f4,26c180b4]
      ckptq: [291529c8,26c12be4] fileq: [29152a40,26c12bec] objq: [26c12c64,27b1d0b8]
      ckptq: [233f6204,26c18034] fileq: [233f620c,26c1803c] objq: [26c180b4,233f6284]
      ckptq: [26c12b34,233f6204] fileq: [26c12b3c,233f620c] objq: [233f6284,26c12bb4]
      ckptq: [26c12be4,26c127c4] fileq: [26c12bec,26c127cc] objq: [26c12844,26c12c64]
      ckptq: [26c12874,233f6364] fileq: [26c1287c,233f636c] objq: [233f63e4,26c128f4]
      ckptq: [26c127c4,233f6414] fileq: [26c127cc,233f641c] objq: [233f6494,26c12844]
      ckptq: [29150a60,24ff50d4] fileq: [29150a9c,24ff50dc] objq: [27b37f18,27b37f18]
      ckptq: [24ff5184,29150a60] fileq: [24ff518c,29150a9c] objq: [27b37888,27b37888]
      ckptq: [233f6364,26c12924] fileq: [233f636c,26c1292c] objq: [26c129a4,233f63e4]

在sga中存在一塊記憶體區域用於記錄這個檢查點佇列
select name,bytes from v$sgastat where upper(name) like '%CHECKPOINT%';

SQL> select name,bytes from v$sgastat where upper(name) like '%CHECKPOINT%';

NAME                            BYTES
-------------------------- ----------
Checkpoint queue               128320

從oracle10g開始,資料庫中額外增加了物件檢查點佇列(object queue,objq)用於記錄物件檢查點資訊:
    BH (0x24ff61dc) file#: 3 rdba: 0x00c00a6c (3/2668) class: 1 ba: 0x24eee000
      set: 3 blksize: 8192 bsi: 0 set-flg: 2 pwbcnt: 46
      dbwrid: 0 obj: 8780 objn: 8780 tsn: 2 afn: 3
      hash: [29115d3c,29115d3c] lru: [24ff62e0,24ff60d0]
      lru-flags:
      ckptq: [24ff5184,29150a60] fileq: [24ff518c,29150a9c] objq: [27b37888,27b37888]
      st: XCURRENT md: NULL tch: 35
      flags: buffer_dirty gotten_in_current_mode block_written_once
              redo_since_read
      LRBA: [0x5.2e7.0] HSCN: [0x0.11546d] HSUB: [1]
      buffer tsn: 2 rdba: 0x00c00a6c (3/2668)
      scn: 0x0000.0011546d seq: 0x01 flg: 0x02 tail: 0x546d0601
      frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

共享池中分配了相關記憶體用於OBJECT QUEUE:
select * from v$sgastat where name like 'object queue%';
SQL> select * from v$sgastat where name like 'object queue%';

POOL         NAME                            BYTES
------------ -------------------------- ----------
shared pool  object queue hash table d        3040
shared pool  object queue hash buckets       69632
shared pool  object queue                    16352

下面來看一下控制檔案以及增量檢查點的協同工作,以下輸出來自oracle10g,兩次level 8級控制檔案的轉儲.
第一部分重要資訊是控制檔案的seq號,控制檔案隨著資料庫的變化而增進版本.
[oracle@jingyong udump]$ diff jingyong_ora_4445.trc jingyong_ora_4463.trc
1c1
< /u01/app/oracle/admin/jingyong/udump/jingyong_ora_4445.trc
---
> /u01/app/oracle/admin/jingyong/udump/jingyong_ora_4463.trc
13c13
< Unix process pid: 4445, image: oracle@jingyong (TNS V1-V3)
---
> Unix process pid: 4463, image: oracle@jingyong (TNS V1-V3)
15,18c15,18
< *** 2013-01-18 05:40:06.832
< *** SERVICE NAME:(SYS$USERS) 2013-01-18 05:40:06.797
< *** SESSION ID:(159.15) 2013-01-18 05:40:06.797
< DUMP OF CONTROL FILES, Seq # 4498 = 0x1192
---
> *** 2013-01-18 05:44:49.284
> *** SERVICE NAME:(SYS$USERS) 2013-01-18 05:44:49.258
> *** SESSION ID:(159.21) 2013-01-18 05:44:49.258
> DUMP OF CONTROL FILES, Seq # 4499 = 0x1193
23c23
<       Control Seq=4498=0x1192, File size=450=0x1c2
---
>       Control Seq=4499=0x1193, File size=450=0x1c2
44c44
<  Database checkpoint: Thread=1 scn: 0x0000.00114550
---
>  Database checkpoint: Thread=1 scn: 0x0000.00115af8
接下來是控制檔案檢查點scn,增量檢查點不斷增進的內容之一:
66c66
<  Controlfile Checkpointed at scn:  0x0000.001145c1 01/18/2013 05:38:56
---
>  Controlfile Checkpointed at scn:  0x0000.00115af8 01/18/2013 05:44:37
96,97c96,97

檢查點記錄之後是RBA資訊,檢查點和redo相關聯在這裡實現,透過以下資訊可以注意到,透過增量檢查點之後,而low cache rba從0x5.307.0增進到0x5.412.0,low cache rba是下一次恢復的起點,而on disk rba則是指已經寫入磁碟(redo log file)的rba地址.
這就是前滾恢復能夠到達的終點.增量檢查點的作用由此體現:
< low cache rba:(0x5.307.0) on disk rba:(0x5.407.0)
< on disk scn: 0x0000.00115a04 01/18/2013 05:33:13
---
> low cache rba:(0x5.412.0) on disk rba:(0x5.442.0)
> on disk scn: 0x0000.00115af9 01/18/2013 05:44:38
99c99

最後一部分是heartbeat心跳資訊,每3秒更新一次用於驗證例項的存活性:
< heartbeat: 805047415 mount id: 3142683107
---
> heartbeat: 805047509 mount id: 3142683107
透過以上分析可以清晰地看到增量檢查點的實施過程,因為增量檢查點可以連續進行,所以檢查點rba可以比常規點更接近資料庫的最後狀態,從而在資料庫的例項恢復中可以極大地減少恢復時間.而且,透過增量檢查點,dbwr可以持續進行寫出,從而避免了常規檢查點出發的峰值,寫入對於I/O的過度徵用.

顯而易見的是,增量檢查點明顯優於常規的完全檢查點,所以在引入檢查點佇列之後,資料庫正常情況下執行的都是增量檢查點,從oracle8i開始,完全檢查點僅僅在以下兩種情況下出現:
alter system checkpoint;
shutdown(除了abort方式外)
log switch事件同樣是觸發的增量檢查點,但是在log switch觸發的檢查點會促使資料檔案頭與控制檔案資訊的同步

log_checkpoints_to_alert引數
在資料庫中,可以設定初始化引數log_checkpoints_to_alert為true,則資料庫會將檢查點的執行情況記入警告日誌檔案中,這個引數的初始值為false:
SQL> show parameter checkpoints_to

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_checkpoints_to_alert             boolean     FALSE
SQL> alter system set log_checkpoints_to_alert=true;

System altered.

當資料庫執行各類檢查點進,日誌檔案中會記錄詳細資訊,以下是來自oracle 10g的警告日誌檔案中的資訊摘錄.注意以下資訊中,共發生了兩次檢查點,觸發條件都是log switch,在日誌中,注意rba資訊和檢查點scn同時出現,這就是檢查點佇列的作用,log switch檢查點的特別之處在於,需要同時在控制檔案和資料檔案頭上標記檢查點進度
[oracle@jingyong bdump]$ tail -20 alert_jingyong.log
Fri Jan 18 06:12:00 2013
Beginning log switch checkpoint up to RBA [0x8.2.10], SCN: 1138121
Thread 1 advanced to log sequence 8
  Current log# 2 seq# 8 mem# 0: /u01/app/oracle/product/10.2.0/oradata/jingyong/redo02.log
Fri Jan 18 06:12:21 2013
Beginning log switch checkpoint up to RBA [0x9.2.10], SCN: 1138140
Thread 1 advanced to log sequence 9
  Current log# 3 seq# 9 mem# 0: /u01/app/oracle/product/10.2.0/oradata/jingyong/redo03.log
Fri Jan 18 06:17:12 2013
Completed checkpoint up to RBA [0x8.2.10], SCN: 1138121
Fri Jan 18 06:17:30 2013
Completed checkpoint up to RBA [0x9.2.10], SCN: 1138140

從以上資訊還可以觀察到,檢查點的觸發和檢查點完成具有一定的時間間隔,這進一步說明,檢查點僅僅是一個資料庫事件,發生檢查點時ckpt程式負責通知dbwr執行寫出,但是檢查點不會等待寫出完成,它會在下一次觸發時寫出上一次成功完成的檢查點資訊.

在警告日誌檔案中,可能還會看到Incremental checkpoint的資訊,這些資訊和檢查點的另外一個觸發條件有關.為了保證檢查點不會滯後整個日誌檔案,oracle限制最長的檢查點跨度不超過最小日誌大小的90%.所以資料庫在執行過程中會根據log tail進行計算,主動觸發增量檢查點.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26015009/viewspace-752941/,如需轉載,請註明出處,否則將追究法律責任。

相關文章