Skip to content

Oracle - 27. page

通过x$KFDAT确认asm file的au信息

X$KFDAT (metadata, disk-to-AU mapping table)

该视图的结构图,以及字段含义
x$kfdat

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 DISKS中定位表行在系统DISK中的物理偏移位置

该部分也是承接从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 DISKS中确定DATAFILE的存储位置

承接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的一个特性,初衷是为了加速失败事务的回滚,缩小回滚时间,Oracle设计这个特性的初衷大多时候都是实现了,但是在一些情况下,这个初衷变成了硬伤,就像七伤拳一样,伤害是不错,但是自己也要受几份内伤。最近碰到2次因为这个特性导致的数据库hang或者部分业务hang的情况。

我根据经验总结一翻并行回滚的情况怕遇见2种情况:

1.并行回滚相关的bug,此类bug有不少
2.大事务的回滚

相关bug:
pxre bugs

关于事务恢复的东西可以参考文章: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.系统中存在死事务

dead tran
3.系统中存在一个回滚事务预估回滚到8月10号

tx recoerinfo

通过awr和收集的信息确定了问题的根源应该就是并行回滚。当然多个并行的回滚进程并没有去判断,在windows平台在系统级别我跳过了这步,为了尽快恢复业务,随即确认了验证性的解决方案,对fast_start_parallel_rollback进行在线变更为false,在对此参数设置不同值的时候,smon进程会停止对该事务的恢复并根据新的参数值重新恢复该事务,该参数是动态的,因此改为false后可以遇见的是该事务会串行顺序回滚,并且速度应该不错,结果并没有让我失望,看下图便知:
tx recover after

当然,现场可以通过smon禁止回滚的方式让exp过去,毕竟是生产,有更好的办法,为啥要用oradebug呢?期间的问题还有不少值得思考,比如undo record的争用,并行回滚进程的资源耗用等,这里不做描述了。

建议关注11g数据库password_life_time

Oracle 11g 之前默认的用户时是没有密码过期的限制的,在Oracle 11g 中default的profile启用了密码过期时间是180天,也就是password_life_time值为180,虽然是个小细节,但是很多客户在迁移到11g后有规律性的都在半年后出现了密码错误无法登陆的问题.

如下:

select * from dba_profiles where profile='DEFAULT' and resource_name='PASSWORD_LIFE_TIME';

PROFILE       RESOURCE_NAME       RESOURCE LIMIT
------------ -------------------- -------- -------
DEFAULT       PASSWORD_LIFE_TIME  PASSWORD 180

当过期时候系统会报错ORA-28002.当遭遇这个问题时候可以通过以下方式解决:

    1.新建profile,对用户指定新的profile.
    2.通过对用户重设密码(密码可以和原来一样).

    命令为:

    alter user username identified by password.
    

    3.针对默认的profile的password_life_time设置为unlimited

    命令为:

    alter profile default limit PASSWORD_LIFE_TIM 180.

以下是profile里的关于password的设置类目解释:

    FAILED_LOGIN_ATTEMPTS
    设定登录到Oracle 数据库时可以失败的次数。一旦某用户尝试登录数据库的达到该值时,该用户的帐户就被锁定,只能由DBA能解锁。
    PASSWORD_LIFE_TIME
    设定口令的有效时间(天数),一旦超过这一时间,必须重新设口令。缺省为180天(11g,10gUNLIMITED).
    PASSWORD_REUSE_TIME
    许多系统不许用户重新启用过去用过的口令。该资源项设定了一个失效口令要经过多少天,用户才可以重新使用该口令。缺省为UNLIMITED.
    PASSWORD_REUSE_MAX
    重新启用一个先前用过的口令前必须对该口令进行重新设置的次数(重复用的次数)。
    PASSWORD_LOCK_TIME
    设定帐户被锁定的天数(当登录失败达到FAILED_LOGIN_ATTEMPTS时)。
    PASSWORD_GRACE_TIME
    设定在口令失效前,给予的重新设该口令的宽限天。当口令失效之后回,在登录时会出现警告信息显示该天数。如果没有在宽限天内修改口令,口令将失效。
    PASSWORD_VERITY_FUNCTION
    该资源项允许调用一个PL/SQL 来验证口令。Oracle公司已提供该应用 的脚本,但是只要愿意的话,用户可以制定自己的验证脚本。该参数的设定就是PL/SQL函数的名称。缺省为NULL.