关于v$视图的定义我们都知道可以通过以下的方式获取:
select * from v$fixed_view_definition where view_name like '%ASM%'; select * from v$fixed_table where name like 'X$KF%';
X$KFDAT (metadata, disk-to-AU mapping table)
example:
查找spfile的au信息: sys@+ASM1> select GROUP_KFDAT,NUMBER_KFDAT,AUNUM_KFDAT from x$kfdat where fnum_kfdat=(select file_number from v$asm_alias where name='spfiletest1.ora'); GROUP_KFDAT NUMBER_KFDAT AUNUM_KFDAT ----------- ------------ ----------- 1 3 101 1 20 379
通过以上可以知道,spfile存在在1号diskgroup的3号磁盘和20号磁盘的2个au,文件所在位置在3号磁盘的相对硬盘第一个au的位置为101号,在20号磁盘相对的位置为379号.x$kfdat的AUNUM_KFDAT字段与x$kffxp视图中的au_kffxp为同一信息.我的diskgroup的为normal冗余模式,所以3.101au和20.379au为mirror关系,可以通过x$kffxp.xnum_kffxp验证,mirror的2个au相关的extent number 一致.x$kfdat与x$kffxp有些字段是关联的.
在12c的asm中,oracle在asmcmd中新增2个命令来确认asm file相关au信息,分别为mapextent以及map au:
example:
ASMCMD> mapextent '+ORCL_MYTEST/ORCL/DATAFILE/mytest.256.8332901607' 1 Disk_Num AU Extent_Size 1 211 1 0 211 1 ASMCMD> mapau usage: mapau [--suppressheader] <dg number> <disk number> <au> help: help mapau ASMCMD> mapau 1 1 107 File_Num Extent Extent_Set 261 1273 636
该部分也是承接从ASM直接读取数据的研究思考,主要是根据asm实例中的x$kffxp视图确定au的位置。
首先准备测试环境的脚本,数据块大小默认为8l:
SQL script to create tablespace col "File name" format a60 col "Tablespace name" format a20 --创建表空间: connect sys/ludatou as sysdba create tablespace test datafile '+TEST' size 5m; grant dba to luda; --创建测试表: connect luda/luda create table luda_tab (n number, name varchar2(16)) tablespace test; insert into luda_tab values (1, 'ASM_TEST'); commit; select ROWID, NAME from luda_tab;
通过以上查询可以知道luda_tab的行块所在位置为数据文件的133号数据块。
SQL> select ROWID from luda_tab; ROWID ------------------ AAAXgDAAHAAAACFAAA SQL> select DBMS_ROWID.ROWID_BLOCK_NUMBER('AAAXgDAAHAAAACFAAA') "Block number" from DUAL; Block number ------------ 133
数据库块大小为8k
SQL> show parameter db_block_size NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ db_block_size integer 8192
TEST表空间的数据文件ASM file number为256
SQL> select f.FILE#, f.NAME "File name", t.NAME "Tablespace name" from V$DATAFILE f, V$TABLESPACE t where t.NAME='TEST' and f.TS# = t.TS#; FILE# File name Tablespace name ---------- -------------------------------------------------- --------------- 7 +TEST/racnode1/datafile/test.256.852905863 TEST
TEST表空间所在的diskgroup号为4
SQL> select GROUP_NUMBER from V$ASM_DISKGROUP where NAME='TEST'; GROUP_NUMBER ------------ 4
4号diskgroup的au size为1M
SQL> select VALUE from V$ASM_ATTRIBUTE where NAME='au_size' and GROUP_NUMBER=4; VALUE ------------------------------------------------------------------------------ 1048576
Diskgroup 4的磁盘信息
SQL> select GROUP_NUMBER, DISK_NUMBER, NAME, path from V$ASM_DISK where GROUP_NUMBER=4; GROUP_NUMBER DISK_NUMBER NAME PATH ------------ ----------- ------------------------------ ------------------------------ 4 0 TEST_0000 /dev/asm_disk_1 4 1 TEST_0001 /dev/asm_disk_2
AU分部与OS磁盘的对应信息
select PXN_KFFXP, -- physical extent number XNUM_KFFXP, -- virtual extent number DISK_KFFXP, -- disk number AU_KFFXP -- allocation unit number from X$KFFXP where NUMBER_KFFXP=256 -- ASM file 256 AND GROUP_KFFXP=4 -- group number 4 order by 1; PXN_KFFXP XNUM_KFFXP DISK_KFFXP AU_KFFXP ---------- ---------- ---------- ---------- 0 0 0 144 1 0 1 144 2 1 1 145 3 1 0 145 4 2 0 146 5 2 1 146 6 3 1 147 7 3 0 147 8 4 0 148 9 4 1 148 10 5 1 149 11 5 0 149
从上面的au分布与os磁盘的对应信息中可以看到256号asm file一共有12个au,au size为1m。由于diskgroup为normal reduncancy模式,所以每一个au在1号磁盘中还有一个镜像,所以一共是12个AU,占用12M。blocksize为8k,所以每个au包含的block数量为1024/8=128个,因为行块所在位置为133号数据块,所以该块应该处于数据文件的第二个au的5(133-128)号8k单元数据块,也就是磁盘/dev/asm_disk_1的145号AU,仔细观察可以发现extent也为对应的号数,由于冗余所以每个extent都有2个。
接下来确认行块在asm_disk_1以及asm_disk_2上
[grid@racnode1 luda]$ strings /dev/asm_disk_1 | grep ASM_TEST ASM_TEST [grid@racnode1 luda]$ strings /dev/asm_disk_2 | grep ASM_TEST ASM_TEST
接着使用dd导出磁盘中145号AU的数据
[grid@racnode1 luda]# dd if=/dev/asm_disk_1 bs=1024k count=1 skip=144 of=AU_145.data 1+0 records in 1+0 records out 1048576 bytes (1.0 MB) copied, 0.031567 seconds, 21.3 MB/s [grid@racnode1 luda]$ [grid@racnode1 luda]$ ls -l AU_145.data -rw-r--r-- 1 grid oinstall 1048576 Aug 13 22:45 AU_145.data [grid@racnode1 luda]$
下来就可以从145号au中取出第5个8k块的数据
[grid@racnode1 luda]$ dd if=AU_145.data bs=8k count=1 skip=4 of=block133.data
使用od观察该块即可找到我们想要的数据ASM_TEST。
[grid@racnode1 luda]$ od -c block133.data 0137760 002 301 002 \b A S M _ T E S T 001 006 i 356Looks good
到此通过AU与OS磁盘的映射关系,验证了可以找到对应行的数据。解释了如何通过asm直接读取object的基本原理。
承接ASM恢复时间的研究思考,这里补充从ASM中恢复出数据文件的需要知道细节部分。
首先找到asm的file directory的物理位置:
[oracle@rac1 ~]$ kfed read /dev/raw/raw1 aunum=0 blknum=0 kfbh.endian: 1 ; 0×000: 0×01 kfbh.hard: 130 ; 0×001: 0×82 kfbh.type: 1 ; 0×002: KFBTYP_DISKHEAD …… kfdhdb.blksize: 4096 ; 0x0ba: 0×1000 kfdhdb.ausize: 1048576 ; 0x0bc: 0×00100000 kfdhdb.mfact: 113792 ; 0x0c0: 0x0001bc80 kfdhdb.dsksize: 3067 ; 0x0c4: 0x00000bfb kfdhdb.pmcnt: 2 ; 0x0c8: 0×00000002 kfdhdb.fstlocn: 1 ; 0x0cc: 0×00000001 kfdhdb.altlocn: 2 ; 0x0d0: 0×00000002 kfdhdb.f1b1locn: 2 ; 0x0d4: 0×00000002
从结果里我们可以看到,file directory的第1个block在AU2上,而从10-12c中的研究分析,ASM的1号文件的file dir的地址都在0号盘的au2上,如果到这里看不懂,研究下asm的metadata文件1-255。
接下来看一下AU2的1号block:
[oracle@rac1 ~]$ kfed read /dev/raw/raw1 aunum=2 blknum=1 kfbh.endian: 1 ; 0×000: 0×01 kfbh.hard: 130 ; 0×001: 0×82 kfbh.type: 4 ; 0×002: KFBTYP_FILEDIR …… kfffdb.usm: ; 0x0a0: length=0 <strong>kfffde[0].xptr.au: 2 ; 0x4a0: 0×00000002</strong> kfffde[0].xptr.disk: 0 ; 0x4a4: 0×0000 kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 kfffde[0].xptr.chk: 40 ; 0x4a7: 0×28 kfffde[1].xptr.au: 2 ; 0x4a8: 0×00000002 kfffde[1].xptr.disk: 1 ; 0x4ac: 0×0001 kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0 kfffde[1].xptr.chk: 41 ; 0x4af: 0×29 kfffde[2].xptr.au: 4294967294 ; 0x4b0: 0xfffffffe kfffde[2].xptr.disk: 65534 ; 0x4b4: 0xfffe kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0 kfffde[2].xptr.chk: 42 ; 0x4b7: 0x2a <strong>kfffde[3].xptr.au: 93 ; 0x4b8: 0x0000005d</strong> kfffde[3].xptr.disk: 0 ; 0x4bc: 0×0000 kfffde[3].xptr.flags: 0 ; 0x4be: L=0 E=0 D=0 C=0 S=0 kfffde[3].xptr.chk: 119 ; 0x4bf: 0×77 kfffde[4].xptr.au: 93 ; 0x4c0: 0x0000005d kfffde[4].xptr.disk: 1 ; 0x4c4: 0×0001 kfffde[4].xptr.flags: 0 ; 0x4c6: L=0 E=0 D=0 C=0 S=0 kfffde[4].xptr.chk: 118 ; 0x4c7: 0×76 kfffde[5].xptr.au: 4294967294 ; 0x4c8: 0xfffffffe …… kfffde[39].xptr.disk: 65535 ; 0x5dc: 0xffff
从结果里我们可以知道/dev/raw/raw1只有两个file directory,第一个file directory在AU2上,第二个file directory在AU93上。asm的默认au为1m,每个file的dir大小为4k,所以每个au最多只能存储256个file,asm1-255file为metadata,所以通常的数据库数据文件都在第二个AU后(这里建议关注下,如果datafile所占有的au数量非常多,4k信息装不下怎么办?)。
在这里1M AU的情况下对于第二个file directory而言,datafile 1就在block 0里,datafile 2就在block 1里,依次类推,所以datafile 4在block 3里(au的基础单元为os块4k大小),下来观察这个block:
[oracle@rac1 ~]$ kfed read /dev/raw/raw1 aunum=93 blknum=3 kfbh.endian: 1 ; 0×000: 0×01 kfbh.hard: 130 ; 0×001: 0×82 kfbh.type: 4 ; 0×002: KFBTYP_FILEDIR kfbh.datfmt: 1 ; 0×003: 0×01 kfbh.block.blk: 259 ; 0×004: T=0 NUMB=0×103 kfbh.block.obj: 1 ; 0×008: TYPE=0×0 NUMB=0×1 …… kfffdb.spare[15]: 0 ; 0x09c: 0×00000000 kfffdb.usm: ; 0x0a0: length=0 kfffde[0].xptr.au: 211 ; 0x4a0: 0×000000d3 kfffde[0].xptr.disk: 1 ; 0x4a4: 0×0001 kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 kfffde[0].xptr.chk: 106 ; 0x4a7: 0x6a kfffde[1].xptr.au: 211 ; 0x4a0: 0×000000d3 kfffde[1].xptr.disk: 0 ; 0x4ac: 0×0000 kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0 kfffde[1].xptr.chk: 107 ; 0x4af: 0x6b kfffde[2].xptr.au: 212 ; 0x4b0: 0×000000d4 kfffde[2].xptr.disk: 0 ; 0x4b4: 0×0000 kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0 kfffde[2].xptr.chk: 106 ; 0x4b7: 0x6a kfffde[3].xptr.au: 212 ; 0x4b0: 0×000000d4 kfffde[3].xptr.disk: 1 ; 0x4bc: 0×0001 kfffde[3].xptr.flags: 0 ; 0x4be: L=0 E=0 D=0 C=0 S=0 kfffde[3].xptr.chk: 107 ; 0x4bf: 0x6b kfffde[4].xptr.au: 213 ; 0x4c0: 0×000000d5 kfffde[4].xptr.disk: 1 ; 0x4c4: 0×0001 kfffde[4].xptr.flags: 0 ; 0x4c6: L=0 E=0 D=0 C=0 S=0 kfffde[4].xptr.chk: 108 ; 0x4c7: 0x6c kfffde[5].xptr.au: 213 ; 0x4c0: 0×000000d5 kfffde[5].xptr.disk: 0 ; 0x4cc: 0×0000 kfffde[5].xptr.flags: 0 ; 0x4ce: L=0 E=0 D=0 C=0 S=0 kfffde[5].xptr.chk: 109 ; 0x4cf: 0x6d kfffde[6].xptr.au: 214 ; 0x4d0: 0×000000d6 kfffde[6].xptr.disk: 0 ; 0x4d4: 0×0000 kfffde[6].xptr.flags: 0 ; 0x4d6: L=0 E=0 D=0 C=0 S=0 kfffde[6].xptr.chk: 108 ; 0x4d7: 0x6c kfffde[7].xptr.au: 214 ; 0x4d0: 0×000000d6 kfffde[7].xptr.disk: 1 ; 0x4dc: 0×0001 kfffde[7].xptr.flags: 0 ; 0x4de: L=0 E=0 D=0 C=0 S=0 kfffde[12].xptr.au: 4294967295 ; 0×500: 0xffffffff kfffde[12].xptr.disk: 65535 ; 0×504: 0xffff …… kfffde[23].xptr.au: 4294967295 ; 0×558: 0xffffffff kfffde[23].xptr.disk: 65535 ; 0x55c: 0xffff
根据上面的信息可以发现datafile 4在/dev/raw/raw1上的物理存储位置可以看到datafile 4一共占了6个AU,分别是AU211,AU212,AU213,AU214.
并行回滚是oracle的一个特性,初衷是为了加速失败事务的回滚,缩小回滚时间,Oracle设计这个特性的初衷大多时候都是实现了,但是在一些情况下,这个初衷变成了硬伤,就像七伤拳一样,伤害是不错,但是自己也要受几份内伤。最近碰到2次因为这个特性导致的数据库hang或者部分业务hang的情况。
我根据经验总结一翻并行回滚的情况怕遇见2种情况:
1.并行回滚相关的bug,此类bug有不少
2.大事务的回滚
关于事务恢复的东西可以参考文章:ID 1494886.1。这里介绍前天碰到的并行回滚导致阻塞的问题,情况是对某张表进行exp导出,结果很慢很慢,等了一晚上都没导完成,采用create table as select的方式也hang住了,信息传到到我这里时候我的反应是事务阻塞,初始判断应该是在段头或者回滚上的阻塞,远程过去时候,并不急着看系统的总体情况,和客户先沟通一翻情况发生的时候是下午1点多开始的,exp和ctas操作也是1点之后,稍微梳理相关的语句信息后初步决定做这几步操作:
1.分析alert.log
2.分析block=1的进程是否存在,是否存在死事务
3.分析发生情况时候的awr以及ash
4.分析发生情况时候的io/cpu情况
5.分析exp/ctas操作时候exp进程的等待
原本打算根据如上的情况后再做下一步的操作,结果在第3个步骤时候就已经发现了问题。alert日志没有报错已经相关有作用的信息,系统中也没有存在的阻塞进程,而AWR中top 5 event确实和我预测的方向在一条线上,具体看如下:
Top 5 Timed Foreground Events
Event | Waits | Time(s) | Avg wait (ms) | % DB time | Wait Class |
---|---|---|---|---|---|
wait for a undo record | 484,175 | 51,190 | 106 | 79.33 | Other |
db file sequential read | 980,647 | 7,411 | 8 | 11.49 | User I/O |
db file scattered read | 29,860 | 723 | 24 | 1.12 | User I/O |
DB CPU | 354 | 0.55 | |||
read by other session | 50,013 | 269 | 5 | 0.42 | User I/O |
以上的信息提示的非常明显,在1小时内存在大量wait for a undo record等待,而此期间内已经关闭了业务,只有exp和ctas操作,可以进一步的判断阻塞的问题应该和涉及对象存在回滚事务有关,当然现场通过undo的信息确认了回滚的对象确实和exp的对象为同一个,具体的方法可以参考文章 《通过undo record找到对应回滚对象信息》 http://www.ludatou.com/?p=2258。
为了确定是并行回滚导致的问题期间收集了以下信息进行判断:
1.FAST_START_PARALLEL_ROLLBACK参数值为low
2.系统中存在死事务
通过awr和收集的信息确定了问题的根源应该就是并行回滚。当然多个并行的回滚进程并没有去判断,在windows平台在系统级别我跳过了这步,为了尽快恢复业务,随即确认了验证性的解决方案,对fast_start_parallel_rollback进行在线变更为false,在对此参数设置不同值的时候,smon进程会停止对该事务的恢复并根据新的参数值重新恢复该事务,该参数是动态的,因此改为false后可以遇见的是该事务会串行顺序回滚,并且速度应该不错,结果并没有让我失望,看下图便知:
当然,现场可以通过smon禁止回滚的方式让exp过去,毕竟是生产,有更好的办法,为啥要用oradebug呢?期间的问题还有不少值得思考,比如undo record的争用,并行回滚进程的资源耗用等,这里不做描述了。
经过2016到2018,修复了一些bug. 现在从新开放下载 […]