感兴趣的还是记得去看原帖子,笔记有删减,原作者微信公众号:
--1、在一个oracle数据库中,controlfile的作用是什么?
如果把oracle比作一个人,那么controlfile就好比是人的大脑。oracle中的大量运行机制都跟controlfile有种紧密关系,例如介质恢复,实例恢复,检查点等等。
--2、关于controlfile
controlfile block大小:通常是16k
controlfile 读写:所有的 controlfile 的读写操作均由ckpt和dbwr进程来完成,属于io密集型文件。
因此在划分存储时,可以将controlfile和redo log一样,划分到相对较快的disk上。
controlfile 冗余: 一般情况下11g controlfile都会进行冗余(默认建库)保存2 份。ASM环境除外.
----问题:对于linux和unix环境,当前数据处于run的时候,某个controlfile损坏会影响数据库运行吗?
--结论:
如果破坏控制文件最前面的十几个block库会立即宕,如果损坏的在控制文件尾部,库不会宕
为了回答这个问题,这里我们可以做个简单的实验:
--实验一:破坏controlfile的尾部,发现库没影响(重启会影响)
echo "test" >> control02.ctl
--强制 全量检查点、切换日志
SQL> alter system checkpoint;
System altered.
SQL> alter system switch logfile;
System altered.
SQL> alter system switch logfile;
System altered.
--check alert
Thu Aug 29 10:23:58 2024
Thread 1 advanced to log sequence 7 (LGWR switch)
Current log# 1 seq# 7 mem# 0: /oradata/orcl/redo01.log
Thread 1 advanced to log sequence 8 (LGWR switch)
Current log# 2 seq# 8 mem# 0: /oradata/orcl/redo02.log
我们可以看到这里,数据库仍然是正常运行的,尽管前面我破坏了一个控制文件,这是为什么呢?难道是因为其进程持有的句柄并有释放,如下:
ps -ef | grep ckpt | grep -v grep
oracle 25454 1 0 10:20 ? 00:00:00 ora_ckpt_orcl
[oracle@test:/oradata/orcl]$ cd /proc/25454/fd
[oracle@test:/proc/25454/fd]$ ls -l | grep control
lrwx------ 1 oracle oinstall 64 Aug 29 10:25 256 -> /oradata/orcl/control01.ctl
lrwx------ 1 oracle oinstall 64 Aug 29 10:25 257 -> /oradata/orcl/control02.ctl
在句柄没有释放之前,该进程会继续将信息写入到操作系统的cache中,我们也可以通过strace命令来进行进一步观察:
--session 1 trace跟踪
[oracle@test:/proc/25454/fd]$ strace -fr -o /tmp/25454.log -p 25454
strace: Process 25454 attached
--session 2 进行redo 切换:
SQL> alter system switch logfile;
System altered.
SQL>
--观察trace log
25454 3.000269 getrusage(RUSAGE_SELF, {ru_utime={0, 9999}, ru_stime={0, 78527}, ...}) = 0
25454 0.000200 getrusage(RUSAGE_SELF, {ru_utime={0, 9999}, ru_stime={0, 78670}, ...}) = 0
25454 0.000446 times({tms_utime=0, tms_stime=7, tms_cutime=0, tms_cstime=0}) = 430034457
25454 0.000302 times({tms_utime=0, tms_stime=7, tms_cutime=0, tms_cstime=0}) = 430034457
25454 0.000535 pwrite64(256, "\25\302\0\0\3\0\0\0\0\0\0\0\0\0\1\4}\243\0\0\2\0\0\0\0\0\0\0\t\0\0\0"..., 16384, 49152) = 16384
25454 0.001212 pwrite64(257, "\25\302\0\0\3\0\0\0\0\0\0\0\0\0\1\4}\243\0\0\2\0\0\0\0\0\0\0\t\0\0\0"..., 16384, 49152) = 16384
25454 0.001192 times({tms_utime=1, tms_stime=8, tms_cutime=0, tms_cstime=0}) = 430034457
25454 0.000369 semtimedop(28, [{16, -1, 0}], 1, {3, 0}) = -1 EAGAIN (Resource temporarily unavailable)
25454 3.000116 getrusage(RUSAGE_SELF, {ru_utime={0, 10123}, ru_stime={0, 80991}, ...}) = 0
25454 0.000175 getrusage(RUSAGE_SELF, {ru_utime={0, 10134}, ru_stime={0, 81072}, ...}) = 0
25454 0.000212 times({tms_utime=1, tms_stime=8, tms_cutime=0, tms_cstime=0}) = 430034757
25454 0.000192 times({tms_utime=1, tms_stime=8, tms_cutime=0, tms_cstime=0}) = 430034757
25454 0.000258 pread64(256, "\25\302\0\0\1\0\0\0\0\0\0\0\0\0\1\4\377(\0\0\0\0\0\0\0\4 \v@T\260e"..., 16384, 16384) = 16384
25454 0.000203 pread64(256, "\25\302\0\0\20\0\0\0\267\2\0\0\377\377\1\4z\243\0\0\200F\0\0\0\0\0\0\0\0\0\1"..., 16384, 262144) = 16384
25454 0.000162 pread64(256, "\25\302\0\0\22\0\0\0\267\2\0\0\377\377\1\4\326\324\0\0\0\0\0\0\0\0\0\0\300\10;F"..., 16384, 294912) = 16384
25454 0.000193 pread64(256, "\25\302\0\0\23\0\0\0\267\2\0\0\377\377\1\4H\36\0\0\17\0\0\0\r\264\16\0\0\0l\t"..., 16384, 311296) = 16384
25454 0.000232 pwrite64(256, "\25\302\0\0\3\0\0\0\0\0\0\0\0\0\1\4z\243\0\0\2\0\0\0\0\0\0\0\t\0\0\0"..., 16384, 49152) = 16384
25454 0.000430 pwrite64(257, "\25\302\0\0\3\0\0\0\0\0\0\0\0\0\1\4z\243\0\0\2\0\0\0\0\0\0\0\t\0\0\0"..., 16384, 49152) = 16384
25454 0.000432 times({tms_utime=1, tms_stime=8, tms_cutime=0, tms_cstime=0}) = 430034757
25454 0.000241 semtimedop(28, [{16, -1, 0}], 1, {3, 0}) = -1 EAGAIN (Resource temporarily unavailable)
25454 3.000216 getrusage(RUSAGE_SELF, {ru_utime={0, 10158}, ru_stime={0, 82938}, ...}) = 0
25454 0.000172 getrusage(RUSAGE_SELF, {ru_utime={0, 10164}, ru_stime={0, 83007}, ...}) = 0
25454 0.000176 times({tms_utime=1, tms_stime=8, tms_cutime=0, tms_cstime=0}) = 430035057
25454 0.000239 times({tms_utime=1, tms_stime=8, tms_cutime=0, tms_cstime=0}) = 430035057
25454 0.000523 pwrite64(256, "\25\302\0\0\3\0\0\0\0\0\0\0\0\0\1\4\177\243\0\0\2\0\0\0\0\0\0\0\t\0\0\0"..., 16384, 49152) = 16384
25454 0.001065 pwrite64(257, "\25\302\0\0\3\0\0\0\0\0\0\0\0\0\1\4\177\243\0\0\2\0\0\0\0\0\0\0\t\0\0\0"..., 16384, 49152) = 16384
25454 0.000459 times({tms_utime=1, tms_stime=8, tms_cutime=0, tms_cstime=0}) = 430035058
25454 0.000219 semtimedop(28, [{16, -1, 0}], 1, {3, 0}) = -1 EAGAIN (Resource temporarily unavailable)
25454 3.000636 getrusage(RUSAGE_SELF, {ru_utime={0, 10189}, ru_stime={0, 84577}, ...}) = 0
25454 0.000150 getrusage(RUSAGE_SELF, {ru_utime={0, 10189}, ru_stime={0, 84637}, ...}) = 0
通过上面的进程跟踪,我们可以得到什么:
1>进程信息可以在/proc下看到,例如:/proc/25454)
2>对于linux,对于文件的读写,是通过调用函数 pread64, pwrite64 来实现的。
3>我们可以发现检查点进程ckpt 3s触发一次的机制。
4> 对于 pwrite64 的操作,是通过写fd (256,257)2个文件来完成的,其中对应的offset都是 49152,且我们知道这2个被写入的文件(我们知道是controlfile)的block大小是16384)
--pwrite64 函数:ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
5>如果细心的同学,还会发现,这个写的offset位置也是比较特别的 49152,可以看到写入的是controlfile的第3个block(49152/16384=3)。在后面详解controlfi结构时会详细描述。
6>控制文件一直被读写的block都是前面几个,所以控制文件的坏块在尾部不受影响
--实验二:破坏controlfile 前面的部分坏块
dd if=/dev/zero of=control02.ctl bs=8192 skip=3 count=30 conv=notrunc
--conv = notrunc 不截短输出文件
SQL> alter system checkpoint;
alter system checkpoint
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 68812
Session ID: 191 Serial number: 13
--数据库直接崩溃:
Incident details in: /home/oracle/app/oracle/diag/rdbms/orcl/orcl/incident/incdir_13298/orcl_ckpt_68285_i13298.trc
Errors in file /home/oracle/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ckpt_68285.trc:
ORA-00227: corrupt block detected in control file: (block 1, # blocks 1)
--这里补充一下控制文件相关的几个数据库参数:
controlfile_block_size ---控制控制文件block大小,10.2版本之前默认是8192,11g是0
_controlfile_enqueue_holding_time ---表示controlfile被enqueue持有的最长时间,11g默认120s
_controlfile_enqueue_timeout ---表示enqueue在等待获取controlfile读写时的超时时间,默认是900秒,超过900s,阻塞进程会被kill掉。
_kill_controlfile_enqueue_blocker ---控制持有controlfile的阻塞进程,在超时后是否被kill,默认是TRUE
_controlfile_update_check ---该参数控制controlfile当前损坏后,是否进行检查,如果进行检查,那么发现某个controlfile不正常,那么数据库会crash.
control_file_record_keep_time ---该参数表示控制文件中的所存记录保留的时间,默认是7天. 主要是备份集copy,备份片,archivelog等信息.
--3、控制文件相关得latch:
不管是完全检查点还是增量检查点,ckpt 进程在操作controlfile之前,都需要先获得相关的latch,其实就是:checkpoint queue latch
select addr,latch#,name from v$latch where name like '%checkpoint%';
ADDR LATCH# NAME
---------------- ---------- --------------------------------------------------
000000006001CD48 175 active checkpoint queue latch
000000006001CDE8 176 checkpoint queue latch
select latch#,child#,level#,name,addr from v$latch_children where NAME like '%checkpoint%';
LATCH# CHILD# LEVEL# NAME ADDR
---------- ---------- ---------- -------------------------------------------------- ----------------
..................
..................
176 9 5 checkpoint queue latch 00000000F214BD68
176 8 5 checkpoint queue latch 00000000F20DFD60
176 7 5 checkpoint queue latch 00000000F20DFC68
176 6 5 checkpoint queue latch 00000000F20DF660
176 5 5 checkpoint queue latch 00000000F20DF568
176 4 5 checkpoint queue latch 00000000F20DEF60
176 3 5 checkpoint queue latch 00000000F20DEE68
176 2 5 checkpoint queue latch 00000000F20DE860
176 1 5 checkpoint queue latch 00000000F20DE768
64 rows selected.
我们可以看到,跟ckpt进程相关的有2个latch,分别是checkpoint queue latch和 active checkpoint queue latch.而 checkpoint queue latch又有64个子latch。
--4、控制文件相关的几个试图
V$CONTROLFILE ---记录controlfile文件名,block size,以及block个数.
V$CONTROLFILE_RECORD_SECTION ---记录controlfile record记录的组成部分
V$BACKUP_CONTROLFILE_DETAILS ---记录controlfile的备份集信息
V$BACKUP_CONTROLFILE_SUMMARY ---controlfile备份的一个汇总信息
select *from v$controlfile;
STATUS NAME IS_REC BLOCK_SIZE FILE_SIZE_BLKS
-------------- ------------------------------ ------ ---------- --------------
/oradata/orcl/control01.ctl NO 16384 594
/oradata/orcl/control02.ctl NO 16384 594
这里我们重点介绍前面2个试图的基表,因为通过前面2个试图的基表,我们可以很容易了解controlfile的结构:
select VIEW_DEFINITION from V$FIXED_VIEW_DEFINITION where view_name='GV$CONTROLFILE';
VIEW_DEFINITION
--------------------------------------------------------------------------------------------------------------------------------------------
select inst_id,decode(bitand(cfflg,1),0,'',1,'INVALID'),cfnam, decode(bitand(cffl2,1),0,'NO','YES'), cfbsz, cffsz from x$kcccf
select VIEW_DEFINITION from V$FIXED_VIEW_DEFINITION where view_name='GV$CONTROLFILE_RECORD_SECTION';
VIEW_DEFINITION
--------------------------------------------------------------------------------------------------------------------------------------------
select inst_id,decode(indx,0,'DATABASE',1, 'CKPT PROGRESS', 2, 'REDO THREAD',3,'REDO LOG',4,'DATAFILE',5,'FILENAME',6,'TABLESPACE',7,'TEMPOR
ARY FILENAME',8,'RMAN CONFIGURATION',9,'LOG HISTORY',10,'OFFLINE RANGE',11,'ARCHIVED LOG',12,'BACKUP SET',13,'BACKUP PIECE',14,'BACKUP DATAF
ILE',15, 'BACKUP REDOLOG',16,'DATAFILE COPY',17,'BACKUP CORRUPTION',18,'COPY CORRUPTION',19,'DELETED OBJECT',20,'PROXY COPY',21,'BACKUP SPFI
LE',23,'DATABASE INCARNATION',24,'FLASHBACK LOG',25, 'RECOVERY DESTINATION', 26,'INSTANCE SPACE RESERVATION', 27, 'REMOVABLE RECOVERY FILES'
, 28, 'RMAN STATUS', 29, 'THREAD INSTANCE NAME MAPPING', 30, 'MTTR', 31, 'DATAFILE HISTORY', 32, 'STANDBY DATABASE MATRIX', 33, 'GUARANTEED
RESTORE POINT', 34, 'RESTORE POINT', 35, 'DATABASE BLOCK CORRUPTION', 36, 'ACM OPERATION', 37, 'FOREIGN ARCHIVED LOG', 'UNKNOWN'),rsrsz,rsnu
m,rsnus,rsiol,rsilw,rsrlw from x$kccrs where indx not in (22)
看上去本质上就是查询2个x$基表,分别是x$kcccf,x$kccrs:
SQL> desc x$kcccf;
Name Null? Type
----------------------------------------------------- -------- ------------------------------------
ADDR RAW(8) --位于sga中的地址
INDX NUMBER --controlfie记录的类型
INST_ID NUMBER --实例编号
CFFLG NUMBER --表示状态
CFNAM VARCHAR2(513) --文件名
CFFL2 NUMBER
CFBSZ NUMBER --block size
CFFSZ NUMBER --block 总数
select * from x$kcccf;
ADDR INDX INST_ID CFFLG CFNAM CFFL2 CFBSZ CFFSZ
---------------- ---------- ---------- ---------- -------------------------------------------------- ---------- ---------- ----------
00002AAAADEF94F0 0 1 0 /oradata/orcl/control02.ctl 0 16384 594
00002AAAADEF94F0 1 1 0 /oradata/orcl/control02.ctl 0 16384 594
SQL> desc x$kccrs
Name Null? Type
----------------------------------------------------- -------- ------------------------------------
ADDR RAW(8) --位于sga中的地址
INDX NUMBER --controlfie记录的类型
INST_ID NUMBER --实例编号
RSRSZ NUMBER --record size大小(单位是byte)
RSNUM NUMBER --在该section内可用的record slot数量
RSNUS NUMBER ---在该section被使用的record slot数量
RSIOL NUMBER --Index of Oldest(可重用)
RSILW NUMBER --Index of Last Written (可重用)
RSRLW NUMBER --Recid of Last Written (可重用)
SQL>
SQL> select * from x$kccrs ;
ADDR INDX INST_ID RSRSZ RSNUM RSNUS RSIOL RSILW RSRLW
---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
00002AAAADEF4810 0 1 316 1 1 0 0 0
00002AAAADEF4810 1 1 8180 11 0 0 0 0
00002AAAADEF4810 2 1 256 8 1 0 0 0
00002AAAADEF4810 3 1 72 16 3 0 0 3
00002AAAADEF4810 4 1 520 100 4 0 0 16
00002AAAADEF4810 5 1 524 2298 8 0 0 0
00002AAAADEF4810 6 1 68 100 5 0 0 1
00002AAAADEF4810 7 1 56 100 1 0 0 10
00002AAAADEF4810 8 1 1108 50 0 0 0 0
00002AAAADEF4810 9 1 56 292 12 1 12 12
00002AAAADEF4810 10 1 200 163 0 0 0 0
.....................
00002AAAADEF4810 35 1 80 8384 0 0 0 0
00002AAAADEF4810 36 1 104 64 6 0 0 0
00002AAAADEF4810 37 1 604 1002 0 0 0 0
38 rows selected.
最后来简单总结一下Controlfile的作用。
1. 记录数据库中数据文件和日志文件的信息,包括文件属性,检查点信息等
2. 在恢复时,跟controlfile中的检查点scn信息和datafile 检查点信息进行比较,以此来判断数据文件是介质恢复,还是实例恢复,还是直接正常open数据库.
最后修改时间:2024-10-10 12:32:15
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




