检查点(checkpoint)的本质
检查点只是一个数据库事件,它存在的根本意义在于减少崩溃恢复(crash recovery)时间。
当修改数据时,需要首先将数据读入内存中(Buffer cache),修改数据的同时,oracle会记录重做信息用于恢复。因为有了重做信息的存在,oracle不需要在提交时立即将变化的数据写回磁盘,重做的存在也正是为了在数据库崩溃之后,数据可以恢复。
最常见的情况,数据库可能因为断电而crash,那么内存中修改过的,尚未写入文件的数据将会丢失。在下一次数据库启动之后,oracle可以通过重做日志进行事务前滚,将数据库恢复到崩溃之前的状态,然后数据库可以打开提供使用,之后oracle可以将未提交的事务进行回滚。
在这个过程中,通常大家最关心的是数据库要经历多久才能打开。也就是需要读取多少重做日志才能完成前滚,检查点的存在就是为了缩短这个恢复时间。
当检查点发生时,Oracle会通过DBWR进程,把修改过的数据,也就是此checkpoint scn之前的脏数据从Buffer Cashe写入磁盘,当写入完成之后,CKPT进程更新控制文件和数据文件头。
Checkpoint SCN 可以从数据库中查询得到:
SQL> Select file# , checkpoint_change# , to_char(checkpoint_time ,'yyyy-mm-dd hh24:mi:ss') CPT from v$datafile;
FILE# CHECKPOINT_CHANGE# CPT
---------- ------------------ -------------------
1 40340857 2013-05-07 05:01:02
2 40340857 2013-05-07 05:01:02
3 40340857 2013-05-07 05:01:02
4 40340857 2013-05-07 05:01:02
5 40340857 2013-05-07 05:01:02
6 40340857 2013-05-07 05:01:02
7 40340857 2013-05-07 05:01:02
7 rows selected
SQL> select dbid , checkpoint_change# from v$database;
DBID CHECKPOINT_CHANGE#
---------- ------------------
1332940841 40340857
在检查点完成之后,此检查点之前修改过的数据都已经写回磁盘,重做日志文件中的相应重做记录对于崩溃/实例恢复不再有用。
图1-1中标记了3个日志组,假定在T1时间点,数据库完成并记录了最后一次检查点,在T2时刻数据库crash。那么在下次数据库启动时,T1时间点之前的redo不再需要进行恢复,oracle需要重新应用的就是时间点T1至T2之间数据库生成的重做日志。
图1-1 检查点之前的redo不需进行恢复
从图1-1中也可以很容易地看出,检查点的频度对于数据库的恢复时间具有极大的影响,如果检查点的频度高,那么恢复时需要应用的重做日志就相对得少,恢复时间就可以缩短。然而,需要注意的是,数据库内部操作的相关性极强,过于频繁的检查点同样会带来性能问题,尤其是更新频繁的数据库。所以数据库的优化是一个系统工程,不能草率。
检查点分类
在Oracle 8之前,Oracle实施的检查点被称为常规检查点,这类检查点按一定的条件触发,从Oracle 8开始,Oracle引入了增量检查点的概念。
和以前的版本相比,在新版本中,Oracle主要引入了检查点队列机制,在数据库内部,每一个脏数据块都会被移动到检查点队列,按照Low RBA的顺序来排序,如果一个数据块进行过多次修改,该数据块在检查点队列上的顺序并不会发生变化。
当执行检查点时,DBWR从检查点队列按照Low RBA的顺序写出,实例检查点因此可以不断增进、阶段性的,CKPT进程使用非常轻量级的控制文件更新协议,将当前的最低RBA导入控制文件。
因为增量检查点可以连续地进行,因此检查点RBA可以比常规检查点更接近数据库的最后状态,从而在数据库的实例恢复中可以极大减少恢复时间。
而且,通过增量检查点,DBWR可以持续进行写出,从而避免了常规检查点出发的峰值写入对于I/O的过度征用,通过图1-2可以清楚地看到这一改进的意义。
图1-2增量检查点对DBWR的影响
SQL> select * from v$version where rownum<2;
BANNER
---------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
SQL> col parameter for a30;
SQL> col value for a20;
SQL> select * from v$option Where Parameter = 'Fast-Start Fault Recovery';
PARAMETER VALUE
------------------------------ --------------------
Fast-Start Fault Recovery TRUE
注意:当Fast-Start Fault Recovery的参数值为TURE的时候表示启动了这个组件。
该组件包含3个主要特性,可以加快系统在故障后的恢复,提高系统的可用性.
Fast-Start checkpointing
Fast-Start On-Demand Rollback
Fast-Start Paralled Rollback
这三个选项,都是为了加快系统在故障后的恢复,提高系统的可用性。
Fast-Start checkpointing特性在oracle8i中主要通过参数Fast_Start_IO_TARGET来实现;
在oracle9i中,Fast-Start checkpointing 主要通过参数Fast_Start_MTTR_TARGET来实现。
Fast_Start_MTTR_TARGET
Fast_Start_MTTR_TARGET参数从oracle9i开始引入,该参数定义数据库进行crash恢复的时间,单位是秒,取值范围是在0-3600秒之间。
在oracle 9i中,oracle推荐设置这个参数代替Fast_Start_IO_TARGET、LOG_CHECKPOINT_TIMEOUT及LOG_CHECKPOINT_INTERVAL参数。
缺省情况下,在oracle9i中,Fast_Start_IO_TARGET和LOG_CHECKPOINT_INTERVAL参数已经被设置为0。
SQL> show parameter fast_start_io;
NAME TYPE VALUE
------------------------------------ ----------- --------------
fast_start_io_target integer 0
SQL> show parameter interval;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
log_checkpoint_interval integer 0
从oracle9i2R开始,oracle引入了一个新的视图提供MTTR建议:
SQL> select MTTR_TARGET_FOR_ESTIMATE MttrEst,
ADVICE_STATUS AD ,
DIRTY_LIMIT DL,
ESTD_CACHE_WRITES ESTCW,
ESTD_CACHE_WRITE_FACTOR ESTCWF,
ESTD_TOTAL_WRITES ESTW,
ESTD_TOTAL_WRITE_FACTOR ETWF,
ESTD_TOTAL_IOS ETIO
From v$mttr_target_advice;
MTTREST AD DL ESTCW ESTCWF ESTW ETWF ETIO
-------------------------------------------------------------------------------------------------------
34 ON 1000 22610363 1.3382 86049188 1.0711 1658237817
90 ON 7157 18841862 1.1151 82280687 1.0242 1654469316
180 ON 17081 16896371 1.0 80335196 1.0 1652523825
170 ON 27005 16136315 0.955 79575140 0.9905 1651763769
360 ON 36929 15662363 0.927 79101188 0.9846 1651289817
估计在不同FAST_START_MTTR_TARGET设置下,系统需要执行的I/O次数等操作。用户可以根据数据库的建议,对FAST_START_MTTR_TARGET进行相应调整。
这个建议信息的收集受到oracle9i新引入的初始化参数statisticcs_level的控制,当该参数设置为Typical或All时,MTTR建议信息被收集:
SQL> show parameter statistics_level
NAME TYPE VALUE
-------------------------------- ---------- --------
statistics_level string TYPICAL
也可以通过v$statistics_level视图来查询MTTR Advice的当前设置:
SQL> select * from v$statistics_level
2 where STATISTICS_NAME='MTTR Advice'
3 /
STATISTICS_NAME DESCRIPTION
SESSION_STATUS SYSTEM_STATUS ACTIVATION_LEVEL STATISTICS_VIEW_NAME
SESSION_SETTABLE
-------------------- -------------------------------------------------------------------------------- -------------- -------------
------------------------------------ ----------------
MTTR Advice Predicts the impact of different MTTR settings on number of physical I/Os
ENABLED ENABLED TYPICAL V$MTTR_TARGET_ADVICE NO
数据库当前的实例恢复状态可以通过视图v$instance_recovery查询得到:
SQL> select RECOVERY_ESTIMATED_IOS REIO,
2 ACTUAL_REDO_BLKS ARB,
3 TARGET_REDO_BLKS TRB,
4 LOG_FILE_SIZE_REDO_BLKS LFSRB,
5 LOG_CHKPT_TIMEOUT_REDO_BLKS LCTRB,
6 LOG_CHKPT_INTERVAL_REDO_BLKS LCIRB,
7 FAST_START_IO_TARGET_REDO_BLKS FSIOTRB,
8 TARGET_MTTR TMTTR, //用户设置的参数FAST_START_MTTR_TARGET的值.
9 ESTIMATED_MTTR EMTTR, //根据目前脏块数目和日志块数目,评估的现在进行恢复所需要的时间.
10 CKPT_BLOCK_WRITES CBW //检查点写完的块数目.
11 from v$instance_recovery;
REIO ARB TRB LFSRB LCTRB LCIRB FSIOTRB TMTTR EMTTR CBW
-------------------------------------------------------------------------------------------------------------------
85 360 6273 165888 6273 60 27 135279
从v$instance_recovery视图,可以看到当前数据库估计的平均恢复时间(MTTR)参数:ESTIMATED_MTTR.
ESTIMATED_MTTR的估算值是基于Dirty Buffer的数量和日志块数量得出的,这个参数值告诉我们,如果此时数据库崩溃,那么进行实例恢复将会需要的时间。
在v$instance_recovery视图中,TARGET_MTTR代表的是期望的平均恢复时间,通常该参数应该等于FAST_START_MTTR_TARGET参数设置值(但是如果FAST_START_MTTR_TARGET参数定义的值极大或极小,TARGET_MTTR可能不等于FAST_START_MTTR_TARGET的设置)。
当ESTIMATED_MTTR接近或超过FAST_START_MTTR_TARGET参数设置(v$instance_recovery.TARGET_MTTR)时,系统将会触发检查点,执行写出之后,系统恢复信息将会重新计算:
SQL> /
REIO ARB TRB LFSRB LCTRB LCIRB FSIOTRB TMTTR EMTTR CBW
-------------------------------------------------------------------------------------------------------------------
37 147 2291 165888 2291 60 27 135826
在繁忙的系统中,可能会观察到ESTIMATED_MTTR > TARGET_MTTR,这可能是因为DBWR正忙于写出,甚或出现Checkpoint不能及时完成的情况。
以下案例来自一个真实的生产系统。
当执行查询时发现ESTIMATED_MTTR > TARGET_MTTR:
SQL > /
REIO ARB TRB LFSRB LCSRB LCTRB LCIRB TMTTR EMTTR CBW
----------------------------------------------------------------------------------------------------------------
30337 614392 184320 184320 614392 180 264 3777074
继续查询,ESTIMATED_MTTR继续升高:
SQL > /
REIO ARB TRB LFSRB LCSRB LCTRB LCIRB FSIOTRB EMTTR CBW
----------------------------------------------------------------------------------------------------------------
24059 614392 184320 184320 614392 180 303 3727076
此时查询v$session_wait,发现数据库处于checkpoint incomplete等待:
SQL> select sid,seq#,event from v$session_wait;
SID SEQ# EVNET
------------------------------------------
1 41486 pmon timer
42 213 rdbms ipc reply
4 4511 rdbms ipc message
7 1209 rdbms ipc message
5 6851 rdbms ipc message
8 34701 rdbms ipc message
20 6918 log file switch(checkpoint incomplete)
2 40139 db file parallel write
3 32433 db file parallel write
6 6296 smon timer
查询V$log视图,发现除了Current日志组外,所有日志组都处于Active状态:
SQL > select * from v$log
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARCHIVED STATUS FIRST_CHANGE#
-------------------------------------------------------------------------------------------------------------------------------
1 1 12104 104857600 1 NO ACTIVE 8903567335116
2 1 12105 104857600 1 NO ACTIVE 8903567337657
3 1 12106 104857600 1 NO CURRENT 8903567340158
4 1 12102 104857600 1 NO ACTIVE 8903567324018
5 1 12103 104857600 1 NO ACTIVE 8903567326497
这意味着系统IO存在瓶颈或者系统有突发的大规模写操作。
通过CKPT_BLOCK_WRITES字段,可以看出检查点已经写出的数据块数量,增量检查点的触发以及DBWR的持续写出,都会促使该值增加,我们继续查询,可以观察到随着CKPT_BLOCK_WRITES的增加,ESITIMATED_MTTR开始减少:
SQL > /
REIO ARB TRB LFSRB LCTRB LCIRB FSIOTRB TMTTR EMTTR CBW
---------------------------------------------------------------------------------------------------------------
23132 614392 184320 184320 614392 180 238 3727077
SQL > /
REIO ARB TRB LFSRB LCTRB LCIRB FSIOTRB TMTTR EMTTR CBW
---------------------------------------------------------------------------------------------------------------
23132 614392 184320 184320 614392 180 183 3727088
当系统完成一个检查点之后:
SQL > select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARCHIVED STATUS
FIRST_CHANGE# FIRST_TIME
---------------------------------------------------------------------------------------------------------------------- -----------------------------------------
1 1 12104 10487600 1 NO INACTIVE
8903567335116 2006-4-28 1
2 1 12105 10487600 1 NO ACTIVE
8903567337657 2006-4-28 1
3 1 12106 10487600 1 NO ACTIVE
8903567340158 2006-4-28 1
4 1 12107 10487600 1 NO ACTIVE
8903567342713 2006-4-28 1
5 1 12108 10487600 1 NO CURRENT
8903567345267 2006-4-28 1
可以看到ESTIMATED_MTTR逐渐恢复到一个较为正常的状态:
REIO ARB TRB LFSRB LCTRB LCIRB FSIOTRB TMTTR EMTTR CBW
---------------------------------------------------------------------------------------------------------------
13076 183735 184320 184320 468895 180 138 3727103