介绍Oracle自带的一些ASM维护工具 (kfod/kfed/amdu)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了介绍Oracle自带的一些ASM维护工具 (kfod/kfed/amdu)相关的知识,希望对你有一定的参考价值。

1.前言

ASM(Automatic Storage Management)是Oracle主推的一种面向Oracle的存储解决方式,它是一个管理卷组或者文件系统的软件。眼下已经被RAC环境广泛使用,可是ASM因为其高度的封装性,使得我们非常难知道窥探其内部的原理。ASM假设一旦出现故障,通常都非常难处理。

即便在有非常完备的RMAN备份的情况下,恢复起来都可能须要非常长的时间。

简单的讲ASM是通过一个ASM实例来实现对磁盘的管理。这个和Oracle 实例非常类似。

ASM实例也有SGA和后台进程组成。可是ASM实例相对的工作非常少。所以它的SGA 相对较小。其主要维护一些ASM的元数据,包含磁盘组元数据(disk group metadata)、磁盘元数据(disk metadata)、文件元数据(file metadata),ASM的体系结构例如以下图:

技术分享

ASM实例管理ASM磁盘组由一个个的ASM磁盘组成,每一个磁盘又由多个区组成,每一个区又由多个AU组成,它们共同协作就构成了ASM的基础应用。

2.ASM体系结构

前面说了ASM中的文件整体上来说分为两大类,元文件和数据文件。数据文件包括Oracle的数据文件、控制文件、重做日志文件、归档日志文件等等。对于ASM来说。仅仅要是非元文件,就是数据文件。

每个文件在ASM中都有一个专门的索引號,也就是编号,ASM文件索引號从1開始。

当中前255个,也就是1至255号文件,都是元文件。256之后的是其它各种文件。

元文件里包括了各种ASM的配置、各类数据文件信息还有文件夹、别名等等信息,都是在元文件里的。全部V$ASM_开头视图的信息。都来自元文件里。

当中。1号文件包括全部文件的磁盘占用信息。包括元文件、甚至1号文件自身的空间分布信息,也都是在1号文件内部。每一个文件在它里面占用一个块(4096字节,元数据块大小为4K)的空间。

从256号文件開始,是数据库的各类文件。如果你放在ASM上的第一个文件是一个控制文件A,第二个文件是一个数据文件B。

哪么控制文件A在ASM中的索引號是256,数据文件B的索引號是257。可是这255个元文件并非都有内容。当中仅仅有前9个文件有内容,我们能够通过訪问x$kffxp内部表获取相关的信息,例如以下:

SQL>SELECT number_kffxp file#, disk_kffxp disk#, COUNT(disk_kffxp) extents

  2  FROMx$kffxp

  3 WHERE group_kffxp=1

  4       AND disk_kffxp <> 65534

  5 GROUP BY number_kffxp, disk_kffxp

  6 ORDER BY 1;

     FILE#     DISK#    EXTENTS

-------------------- ----------

         1          0          2

         2          0          1

         3          0         28

         3          3         14

         4          0          5

         4          3          3

         5          0          1

         6         0          1

         8          3          1

         9          0          1

       256          0        482

     .........

       268          3          7

      269          0          1

35 ROWSselected.

file#   1   -file directory

file#   2   -disk directory

file#   3   -active Change Directory(ACD)

file#   4   -continuing Operations Directory (COD)

file#   5   -template directory

file#   6   -alias directory

file#   7   -volume directory

file#   8   -diskUsed Space Directory (USD)

file#   9   -attributes directory

当中1号文件总是開始在0号磁盘2号AU,这是ASM中定位文件的起点。它的作用,有点相当于磁盘上的引导区,在电脑开机后负责将OS启动起来。

每次从ASM中读数据时,Oracle都要先读到1号文件,从中找出要读的目标文件在磁盘上的分布位置,然后再去读取对应的文件的数据。

技术分享

      那么问题来了,0号AU存放的什么信息呢?这个我想大家已经猜到了。就是存放的ASM磁盘头(disk header)信息,也是我们随后会重点介绍的内容,一旦该磁盘配置好后,假设不再对其做其他的操作,这部分内容相对就固定不变,可是ASM中最为脆弱的又是ASM磁盘头。

假设磁盘头逻辑损坏了。即corrupt了,整个磁盘组将不可以mount。依赖于ASM实例的数据库也将不可以訪问ASM磁盘并正常启动。兴许我们会通过kfed工具对其进行解读。

3.kfod和kfed

kfod和kfed是ASM自带的未公开的工具,kfod主要用于在系统级别对ASM信息的查看。而kfed它能够读取和改动ASM磁盘的元数据,对修复一些关键错误很实用,接下来分别介绍和演示下这两个工具。

下面使用的环境数据库版本号都是11gr2

3.1.  kfod介绍

我们曾经要想訪问和查询ASM的信息,仅仅能通过数据库视图进行查询,无法通过操作系统层进行訪问。可是如今我们能够直接通过kfod工具,直接在操作系统层对ASM的相关信息进行查阅,我们先来看下kfod的帮助。输入kfod –h得到结果例如以下:

[[email protected]~]$ kfod -h

KFOD-00101:LRM error [107] while parsing command line arguments

_asm_a/llow_only_raw_disks                 KFOD allow only raw devices[_asm_allow_only_raw_disks=TRUE/(FALSE)]

_asm_l/ibraries           ASMLibraries[_asm_libraries=lib1,lib2,...]

_asms/id             ASM Instance[_asmsid=sid]

a/sm_diskstring           ASM Diskstring[asm_diskstring=discoverystring, discoverystring ...]

c/luster               KFOD cluster[cluster=TRUE/(FALSE)]

db/_unique_name                 db_unique_name for ASMinstance[db_unique_name=dbname]

di/sks                  Disks to discover[disks=raw,asm,badsize,all]

ds/cvgroup          Include group name[dscvgroup=TRUE/(FALSE)]

g/roup                 Disks in diskgroup[group=diskgroup]

h/ostlist              hostlist[hostlist=host1,host2,...]

metadata_a/usize                 AU Size for Metadata SizeCalculation

metadata_c/lients                Client Count for Metadata SizeCalculation

metadata_d/isks                   Disk Count for Metadata SizeCalculation

metadata_n/odes                 Node Count for Metadata SizeCalculation

metadata_r/edundancy                  Redundancy for Metadata SizeCalculation

n/ohdr                 KFOD header suppression[nohdr=TRUE/(FALSE)]

o/p             KFOD options type[OP=DISKS/CANDIDATES/MISSING/GROUPS/INSTS/VERSION/CLIENTS/RM/RMVERS/DFLTDSTR/GPNPDSTR/METADATA/ALL]

p/file                   ASM parameter file[pfile=parameterfile]

s/tatus                Include disk header status[status=TRUE/(FALSE)]

v/erbose              KFOD verbose errors[verbose=TRUE/(FALSE)]

我们能够看到。有大量的參数,差点儿能够轻松的查看ASM的全部信息,如我们曾经要查询ASM的磁盘空间大小和剩余量,必须通过登录实例訪问视图,如今就能够直接通过kfod工具查询,例如以下:

l  查看磁盘组信息

[[email protected]~]$ kfod di=all op=groups

--------------------------------------------------------------------------------

Group          Size          Free Redundancy  Name          

================================================================================

   1:     16378 Mb      14070 Mb     EXTERN  DATA          

   2:       509 Mb        459 Mb     EXTERN  ARCH          

l  查看磁盘组的组成

[[email protected]~]$ kfod di=all group=diskgroup ds=true

--------------------------------------------------------------------------------

 Disk         Size Path                                     DiskGroup   User     Group  

================================================================================

   1:      8189 Mb /dev/asm-disk1                           DATA         oracle   dba    

   2:      8189 Mb /dev/asm-disk2                           DATA         oracle   dba    

   3:       509 Mb /dev/asm-disk3                           ARCH         oracle   dba     

3.2.  kfed介绍

kfod仅仅是能够通过操作系统直接查看ASM的信息。可是前面我们说了,ASM最易出现故障的不是存储数据的本身,而是ASM磁盘头。那怎样訪问和维护磁盘头呢?这就要用到我们介绍的kfed工具。KFED是ASM自带的一个未公开的工具,它能够对ASM元数据进行一系列的操作,重要的是它能够在ASM无法启动的时候也能够工作,对修复一些关键错误很实用(前面介绍的kfod必须在ASM启动的状态下訪问),我们相同先来看下帮助信息。例如以下:

[[email protected]~]$ kfed -h

as/mlib         ASM Library [asmlib=‘lib‘]

aun/um          AU number to examine or update[AUNUM=number]

aus/z           Allocation Unit size in bytes[AUSZ=number]

blkn/um         Block number to examine or update[BLKNUM=number]

blks/z          Metadata block size in bytes[BLKSZ=number]

ch/ksum         Update checksum before each write[CHKSUM=YES/NO]

cn/t            Count of AUs to process[CNT=number]

de/v            ASM device to examine or update[DEV=string]

dm/pall         Don‘t suppress repeated lines whendumping corrupt blocks [DMPALL=YES/NO]

o/p             KFED operation type[OP=READ/WRITE/MERGE/REPAIR/NEW/FORM/FIND/STRUCT]

p/rovnm         Name for provisioning purposes[PROVNM=string]

s/eek           AU number to seek to [SEEK=number]

te/xt           File name for translated block text[TEXT=string]

ty/pe           ASM metadata block type number[TYPE=number]

kfed能够跳过ASM实例直接訪问磁盘。这就能够在一些很规的环境下,如ASM关闭,磁盘组无法mount等对ASM的相关信息进行訪问,在加上其具备的改动功能,能够利用其对ASM进行修复操作,要想了解kfed的修复方法,我们首先来了解下ASM磁盘头,前面我们通过kfod知道了有/dev/asm-disk1、/dev/asm-disk2、/dev/asm-disk3个磁盘作为ASM的磁盘组所使用。我们又知道,磁盘头的信息存放在每一个磁盘0号AU的位置第0号数据块中,那么如今我们就以当中的一个来看一下它的磁盘头究竟存储了那些信息,例如以下:

[[email protected]~]$ kfed read /dev/asm-disk1 aun=0 blkn=0

【01】kfbh.endian:                          1 ; 0x000: 0x01

【02】kfbh.hard:                          130 ; 0x001: 0x82

【03】kfbh.type:                            1 ; 0x002:KFBTYP_DISKHEAD

【04】kfbh.datfmt:                          1 ; 0x003: 0x01

【05】kfbh.block.blk:                       0 ; 0x004: blk=0

【06】kfbh.block.obj:              2147483648 ; 0x008: disk=0

【07】kfbh.check:                   875080645 ; 0x00c:0x3428abc5

【08】kfbh.fcn.base:                     4892 ; 0x010: 0x0000131c

【09】kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000

【10】kfbh.spare1:                          0 ; 0x018: 0x00000000

【11】kfbh.spare2:                          0 ; 0x01c: 0x00000000

【12】kfdhdb.driver.provstr:         ORCLDISK ; 0x000: length=8

【13】kfdhdb.driver.reserved[0]:            0 ; 0x008: 0x00000000

【14】kfdhdb.driver.reserved[1]:            0 ; 0x00c: 0x00000000

【15】kfdhdb.driver.reserved[2]:            0 ; 0x010: 0x00000000

【16】kfdhdb.driver.reserved[3]:            0 ; 0x014: 0x00000000

【17】kfdhdb.driver.reserved[4]:            0 ; 0x018: 0x00000000

【18】kfdhdb.driver.reserved[5]:            0 ; 0x01c: 0x00000000

【19】kfdhdb.compat:                186646528 ; 0x020: 0x0b200000

【20】kfdhdb.dsknum:                        0 ; 0x024: 0x0000

【21】kfdhdb.grptyp:                        1 ; 0x026:KFDGTP_EXTERNAL

【22】kfdhdb.hdrsts:                        3 ; 0x027:KFDHDR_MEMBER

【23】kfdhdb.dskname:               DATA_0000 ; 0x028: length=9

【24】kfdhdb.grpname:                    DATA ; 0x048: length=4

【25】kfdhdb.fgname:                DATA_0000 ; 0x068: length=9

【26】kfdhdb.capname:                         ; 0x088: length=0

【27】kfdhdb.crestmp.hi:             33020845 ; 0x0a8: HOUR=0xdDAYS=0x1d MNTH=0x6 YEAR=0x7df

【28】kfdhdb.crestmp.lo:           1437992960 ; 0x0ac: USEC=0x0MSEC=0x182 SECS=0x1b MINS=0x15

【29】kfdhdb.mntstmp.hi:             33021392 ; 0x0b0: HOUR=0x10DAYS=0xe MNTH=0x7 YEAR=0x7df

【30】kfdhdb.mntstmp.lo:           2467747840 ; 0x0b4: USEC=0x0MSEC=0x1b6 SECS=0x31 MINS=0x24

【31】kfdhdb.secsize:                     512 ; 0x0b8: 0x0200

【32】kfdhdb.blksize:                    4096 ; 0x0ba: 0x1000

【33】kfdhdb.ausize:                  1048576 ; 0x0bc: 0x00100000

【34】kfdhdb.mfact:                    113792 ; 0x0c0: 0x0001bc80

【35】kfdhdb.dsksize:                    8189 ; 0x0c4: 0x00001ffd

【36】kfdhdb.pmcnt:                         2 ; 0x0c8: 0x00000002

【37】kfdhdb.fstlocn:                       1 ; 0x0cc: 0x00000001

【38】kfdhdb.altlocn:                       2 ; 0x0d0: 0x00000002

【39】kfdhdb.f1b1locn:                      2 ; 0x0d4: 0x00000002

【40】kfdhdb.redomirrors[0]:                0 ; 0x0d8: 0x0000

【41】kfdhdb.redomirrors[1]:            65535 ; 0x0da: 0xffff

【42】kfdhdb.redomirrors[2]:            65535 ; 0x0dc: 0xffff

【43】kfdhdb.redomirrors[3]:            65535 ; 0x0de: 0xffff

【44】kfdhdb.dbcompat:              168820736 ; 0x0e0: 0x0a100000

【45】kfdhdb.grpstmp.hi:             33020845 ; 0x0e4: HOUR=0xdDAYS=0x1d MNTH=0x6 YEAR=0x7df

【46】kfdhdb.grpstmp.lo:           1437544448 ; 0x0e8: USEC=0x0MSEC=0x3cc SECS=0x1a MINS=0x15

【47】kfdhdb.vfstart:                     352 ; 0x0ec: 0x00000160

【48】kfdhdb.vfend:                       384 ; 0x0f0: 0x00000180

【49】kfdhdb.spfile:                        0 ; 0x0f4: 0x00000000

【50】kfdhdb.spfflg:                        0 ; 0x0f8: 0x00000000

【51】kfdhdb.ub4spare[0]:                   0 ; 0x0fc: 0x00000000

。。。。

。。(略)

【103】kfdhdb.ub4spare[52]:                  0 ; 0x1cc: 0x00000000

【104】kfdhdb.ub4spare[53]:                  0 ; 0x1d0: 0x00000000

【105】kfdhdb.acdb.aba.seq:                  0 ; 0x1d4: 0x00000000

【106】kfdhdb.acdb.aba.blk:                  0 ; 0x1d8: 0x00000000

【107】kfdhdb.acdb.ents:                     0 ; 0x1dc: 0x0000

【108】kfdhdb.acdb.ub2spare:                 0 ; 0x1de: 0x0000

总共同拥有108行内容,这些内容是什么含义呢?我们来一一解读

第1行:kfbh.endian:小字节(LittleEndian) = 1  大字节(Big Endian) = 0

第2行:kfbh.hard:元文件块大小 默认是0x82

第3行:type_kfbh:类型,磁盘头总是KFBTYP_DISKHEAD

第4行:kfbh.datfmt 数据格式

第5行:kfbh.block.blk磁盘头始终是0

第6行:kfbh.block.obj磁盘在磁盘组中的号

第7行:kfbh.check 校验码,写到磁盘前计算

第8~11行:磁盘头无意义

第12行:kfdhdb.driver.provstr 没有使用Lib包的时候显示为ORCLDISK

第13~18行:kfdhdb.driver.reserved始终为0

第19行:kfdhdb.compat 版本

第20行: kfdhdb.dsknum  0

第21行:kfdhdb.grptyp 冗余策略,共4种冗余策略

   KFDGTP_INVALID    ((kfdgtp)0)  /* Illegal value                    */
   KFDGTP_EXTERNAL    ((kfdgtp)1)  /* Externalredundancy               */
   KFDGTP_NORMAL      ((kfdgtp)2)  /*Normal redundancy                */
   KFDGTP_HIGH       ((kfdgtp)3)  /* High redundancy                  */

第22行:hdrsts_kfdhdb 磁盘状态,共8种状态

   KFDHDR_INVALID    ((kfdhdr)0)  /*   Illegal value                  */
   KFDHDR_UNKNOWN     ((kfdhdr)1)  /*  Disk header block unreadable    */
   KFDHDR_CANDIDATE   ((kfdhdr)2)  /*  No OSM or OS disk header found  */
   KFDHDR_MEMBER     ((kfdhdr)3)  /*   Normal member of the group     */
   KFDHDR_FORMER     ((kfdhdr)4)  /*   Disk dropped cleanly from group */
   KFDHDR_CONFLICT    ((kfdhdr)5)  /*  Header conflicts               */
   KFDHDR_INCOMPAT    ((kfdhdr)6)  /*  Written by incompatible software*/
   KFDHDR_PROVISIONED ((kfdhdr)7)  /*   Disk wasprepared beforehand    */
        參见V$asm_disk
第23行:dskname_kfdhdb 磁盘名称 

第24行:grpname_kfhdb 磁盘组名称

第25行:fgname_kfdhdb: 磁盘名称

第26行:capname_kfdhdb 未使用

第27~28行:fdhdb.crestmp.hi。kfdhdb.crestmp.lo创建时的时间戳

第29~30行:kfdhdb.mntstmp.hi,kfdhdb.mntstmp.lo  Mount时的时间戳

第31行:kfdhdb.secsize 扇区大小

第32行:kfdhdb.blksize块大小

第33行:kfdhdb.ausize AU大小。

第34行:kfdhdb.mfact: 版本号相关,无意义

第35行:kfhdb.dsksize本磁盘包括的AU数量。kfdhdb.ausize *dsksize_kfdhdb = disk size

第36行:kfdhdb.pmcnt  AU的物理地址空间。

第37行:kfdhdb.fstlocn  说明第一个AU后,是用户可用空间。

第37行:kfdhdb.altlocn 说明文件文件夹開始自第二个AU

第38行:kfdhdb.f1b1locn  文件文件夹块1分配单元号

第39~108行:在默认au的情况下,后面的信息基本都变化不大

       这部分信息对于ASM识别磁盘很重要,也正式由于它的重要,11g默认就就对其进行了一个镜像备份,能够通过kefd的repair操作直接恢复。相当的方便。

4.ASM磁盘头的修复

因为磁盘头的信息相对简单并且变化非常小,特别是同一磁盘组的磁盘,每一个磁盘头的信息差点儿一致,而当我们了解了磁盘头的信息后,一旦某个磁盘头的信息出现了问题,我们能够利用其它磁盘头信息然后通过kfed工具对其进行改动和调整,达到修复的目的。当中用得最多的是读取(Read)、修复(Repair)和合并(Merge)三个操作。

4.1.  Repair修复法

首先大家要明白一点,Oracle正由于知道ASM磁盘头的重要性,因此默认情况下,就对其进行了镜像备份。有点类似于控制文件。在每一个ASM文件的第一个AU位置。是磁盘头信息。而第1个AU位置最后第2个数据块中,默认情况下就是对磁盘头信息的镜像备份。如AU的缺省大小是1M时,那个数据块就是254,我们能够查询下:

磁盘头信息:

[[email protected]~]$  kfed read /dev/asm-disk1 aun=0 blkn=0|more

kfbh.endian:                          1 ; 0x000: 0x01

kfbh.hard:                          130 ; 0x001: 0x82

kfbh.type:                            1 ; 0x002:KFBTYP_DISKHEAD

kfbh.datfmt:                          1 ; 0x003: 0x01

kfbh.block.blk:                       0 ; 0x004: blk=0

kfbh.block.obj:              2147483648 ; 0x008: disk=0

kfbh.check:                  1997052059 ; 0x00c:0x7708989b

kfbh.fcn.base:                     4892 ; 0x010: 0x0000131c

kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000

kfbh.spare1:                          0 ; 0x018: 0x00000000

kfbh.spare2:                          0 ; 0x01c: 0x00000000

kfdhdb.driver.provstr:         ORCLDISK ; 0x000: length=8

kfdhdb.driver.reserved[0]:            0 ; 0x008: 0x00000000

。。。。。(下面内容略)

1号AU倒数第二个数据块信息:

[[email protected]~]$  kfed read /dev/asm-disk1 aun=1 blkn=254|more

kfbh.endian:                          1 ; 0x000: 0x01

kfbh.hard:                          130 ; 0x001: 0x82

kfbh.type:                            1 ; 0x002: KFBTYP_DISKHEAD

kfbh.datfmt:                          1 ; 0x003: 0x01

kfbh.block.blk:                     254 ; 0x004: blk=254

kfbh.block.obj:              2147483648 ; 0x008: disk=0

kfbh.check:                  1997052005 ; 0x00c:0x77089865

kfbh.fcn.base:                     4892 ; 0x010: 0x0000131c

kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000

kfbh.spare1:                          0 ; 0x018: 0x00000000

kfbh.spare2:                          0 ; 0x01c: 0x00000000

kfdhdb.driver.provstr:         ORCLDISK ; 0x000: length=8

kfdhdb.driver.reserved[0]:            0 ; 0x008: 0x00000000

。。。。。(下面内容略)

能够看到查询出来的内容相同也是磁盘头内容,这部分是ORACLE自行备份的信息,可是注意该特性仅仅在10.2.0.5及以上版本号才有,10.2.0.4版本号数据库没有这部分信息。

利用dd命令清空当中一个ASM磁盘的磁盘头信息。例如以下

[[email protected]~]$ dd if=/dev/zero of=/dev/asm-disk1 bs=4096 count=1

1+0records in

1+0records out

4096bytes (4.1 kB) copied, 0.00157905 s, 2.6 MB/s

[[email protected]~]$  kfed read /dev/asm-disk1 aun=0blkn=0|more

kfbh.endian:                          0 ; 0x000: 0x00

kfbh.hard:                            0 ; 0x001: 0x00

kfbh.type:                            0 ; 0x002: KFBTYP_INVALID

kfbh.datfmt:                          0 ; 0x003: 0x00

kfbh.block.blk:                       0 ; 0x004: blk=0

kfbh.block.obj:                       0 ; 0x008: file=0

kfbh.check:                           0 ; 0x00c:0x00000000

kfbh.fcn.base:                        0 ; 0x010: 0x00000000

kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000

kfbh.spare1:                          0 ; 0x018: 0x00000000

kfbh.spare2:                          0 ; 0x01c: 0x00000000

7F8A21E3440000000000 00000000 00000000 00000000 [................]

  Repeat 255 times

KFED-00322: Invalid contentencountered during block traversal: [kfbtTraverseBlock][Invalid OSM blocktype][][0]

能够看到,/dev/asm-disk1磁盘的磁盘头信息已经被彻底的损坏。我们再查看ASM视图,看下状态;

SQL>select group_Number,DISK_NUMBER,name,HEADER_STATUS,path from v$asm_disk;

GROUP_NUMBERDISK_NUMBER NAME        HEADER_STATUS                           PATH

         2              1   DATA_0001               MEMBER                /dev/asm-disk2

2             0   DATA_0000                   CANDIDATE                      /dev/asm-disk1

         1              0   ARCH_0000                        MEMBER               /dev/asm-disk3

假设这时候重新启动server,CRS集群也将无法启动,CRS的一些关键信息也是存放在ASM中,曾经遇到这样的情况,我们仅仅能重建ASM,利用备份进行恢复。可是如今我们晓得了磁盘头的备份机制,我们仅仅须要运行一个简单的repair命令,就能够轻松的修复磁盘头信息。例如以下

利用repair命令恢复1号au中的备份信息到0号au磁盘头信息位置。例如以下

[[email protected]~]$ kfed repair /dev/asm-disk1

磁盘头的信息被备份信息恢复了,例如以下:

[[email protected]~]$ kfed read /dev/asm-disk1

kfbh.endian:                          1 ; 0x000: 0x01

kfbh.hard:                          130 ; 0x001: 0x82

kfbh.type:                            1 ; 0x002: KFBTYP_DISKHEAD

kfbh.datfmt:                          1 ; 0x003: 0x01

kfbh.block.blk:                       0 ; 0x004: blk=0

kfbh.block.obj:              2147483648 ; 0x008: disk=0

kfbh.check:                  1997052059 ; 0x00c:0x7708989b

kfbh.fcn.base:                     4892 ; 0x010: 0x0000131c

kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000

kfbh.spare1:                          0 ; 0x018: 0x00000000

kfbh.spare2:                          0 ; 0x01c: 0x00000000

kfdhdb.driver.provstr:         ORCLDISK ; 0x000: length=8

kfdhdb.driver.reserved[0]:            0 ; 0x008: 0x00000000

。。

。。。

。(下面内容略)

4.2.  Merge修复法

Repair修复asm磁盘头信息是最简单、最方便的方法,它主要是利用了ORACLE自己主动镜像备份的原因。可是这个功能仅仅在10.2.0.5之后才有,并且假设一旦备份地方(1号AU,倒数第二个块)的信息也被损坏。这个时候就无法利用Repair方式进行恢复了,假设没有备份,那里恢复起来就会比較的麻烦。

可是假设是一个磁盘组的某个磁盘头出现了问题,我们能够结合保存在磁盘中的文件字典(file directory)和(diskdirectory)信息的来进行磁盘头恢复,由于文件字典(filedirectory)。仅仅保存在磁盘组中当中一个磁盘中,这里以/dev/asm-disk1和/dev/asm-disk2为例。由于是同属一个磁盘组,磁盘组名为DATA,例如以下:

[[email protected]~]$ kfod di=all group=diskgroup ds=true

--------------------------------------------------------------------------------

 Disk         Size Path                                     DiskGroup   User     Group  

================================================================================

  1:       8189 Mb/dev/asm-disk1                          DATA         oracle   dba    

  2:       8189 Mb/dev/asm-disk2                          DATA         oracle   dba    

   3:       509 Mb /dev/asm-disk3                           ARCH         oracle   dba     

我们首先来看下。它们两个磁盘,谁是file directory磁盘,通过例如以下查询:

[[email protected]~]$  kfed read /dev/asm-disk1  |grep f1b1

kfdhdb.f1b1locn:                      2 ; 0x0d4: 0x00000002

[[email protected]~]$  kfed read /dev/asm-disk2  |grep f1b1

kfdhdb.f1b1locn:                      0 ; 0x0d4: 0x00000000

假设查询出来的结果为非0的,就是file directory磁盘,这里我们能够看到,是/dev/asm-disk1这个磁盘中保存的filecdirectory信息。

1.       确认disk directory在磁盘中的位置

[[email protected]~]$  kfed read /dev/asm-disk1  |grep f1b1明白file directory的位置,在2au

kfdhdb.f1b1locn:                      2; 0x0d4: 0x00000002

[[email protected]~]$ kfed read /dev/asm-disk1 aun=2 blkn=2 |grep au |head -5明白disk directory的位置

kfffde[0].xptr.au:                    3 ; 0x4a0: 0x00000003

kfffde[1].xptr.au:           4294967295 ; 0x4a8: 0xffffffff

kfffde[2].xptr.au:           4294967295 ; 0x4b0: 0xffffffff

kfffde[3].xptr.au:           4294967295 ; 0x4b8: 0xffffffff

kfffde[4].xptr.au:           4294967295 ; 0x4c0: 0xffffffff

2.       查看磁盘字典信息,由于我们损坏的是/dev/asm-disk2。因此我们这里仅仅关注kfddde[1]的信息,重点关注红色的6条信息。

[[email protected]~]$ kfed read /dev/asm-disk1 aun=3 blkn=0 |grep name

kfddde[0].dskname:            DATA_0000 ; 0x038: length=9

kfddde[0].fgname:             DATA_0000 ; 0x058: length=9

kfddde[1].dskname:            DATA_0001 ; 0x1f8: length=9

kfddde[1].fgname:             DATA_0001 ; 0x218: length=9

kfddde[2].dskname:                      ; 0x3b8: length=0

kfddde[2].fgname:                       ; 0x3d8: length=0

。。

。。

(下面内容省略)

这里我们知道DATA磁盘组包括了2个磁盘,当中DATA_0000是本磁盘。那么DATA_0001就是损坏的/dev/asm-disk2磁盘了。因此我们仅仅须要查看涉及该磁盘的相关信息,例如以下:

[[email protected]~]$ kfed read /dev/asm-disk1 aun=3 blkn=0 |more

。。。。。。(略)

kfddde[1].entry.incarn:               1 ; 0x1e4: A=1 NUMM=0x0

kfddde[1].entry.hash:                 1 ; 0x1e8: 0x00000001

kfddde[1].entry.refer.number:4294967295; 0x1ec: 0xffffffff

kfddde[1].entry.refer.incarn:         0 ; 0x1f0: A=0 NUMM=0x0

kfddde[1].dsknum:                     1 ; 0x1f4: 0x0001

kfddde[1].state:                      2 ; 0x1f6: KFDSTA_NORMAL

kfddde[1].ddchgfl:                  132 ; 0x1f7: 0x84

kfddde[1].dskname:            DATA_0001 ; 0x1f8: length=9

kfddde[1].fgname:             DATA_0001 ; 0x218: length=9

kfddde[1].crestmp.hi:          33020874 ; 0x238: HOUR=0xa DAYS=0x1eMNTH=0x6 YEAR=0x7df

kfddde[1].crestmp.lo:         574201856 ; 0x23c: USEC=0x0 MSEC=0x268SECS=0x23 MINS=0x8

kfddde[1].failstmp.hi:                0 ; 0x240: HOUR=0x0 DAYS=0x0MNTH=0x0 YEAR=0x0

kfddde[1].failstmp.lo:                0 ; 0x244: USEC=0x0 MSEC=0x0SECS=0x0 MINS=0x0

kfddde[1].timer:                      0 ; 0x248: 0x00000000

kfddde[1].size:                    8189 ; 0x24c: 0x00001ffd

。。。。。

。(略)

3.       依据以上信息,生成/dev/asm-disk2的磁盘头信息(这里能够通过/dev/asm-disk1的磁盘头信息改动)

[[email protected] ~]$ kfed read /dev/asm-disk1aun=0 blkn=0 text=/home/oracle/asm-disk1.txt

利用编辑器打开生成的文件asm-disk1.txt,主要相应改动下面内容

原始的

kfbh.block.obj:    2147483648 ; 0x008: disk=0

kfdhdb.dsknum:   0 ;         0x024: 0x0000

kfdhdb.dskname: DATA_0000 ; 0x028: length=9

kfdhdb.fgname:   DATA_0000 ; 0x068: length=9

kfdhdb.crestmp.hi:33020845 ;  0x0a8: HOUR=0xd DAYS=0x1dMNTH=0x6 YEAR=0x7df

kfdhdb.crestmp.lo:1437992960 ; 0x0ac: USEC=0x0 MSEC=0x182 SECS=0x1b MINS=0x15

kfdhdb.dsksize:    8189;      0x0c4: 0x00001ffd

kfdhdb.f1b1locn:   2 ;        0x0d4: 0x00000002

改动后的

kfbh.block.obj:    2147483649 ; 0x008: disk=1    (按顺序加1)

kfdhdb.dsknum:   1 ;         0x024: 0x0001   (參照kfddde[1].dsknum

kfdhdb.dskname: DATA_0001 ; 0x028: length=9  (參照kfddde[1].dskname

kfdhdb.fgname:   DATA_0001 ; 0x068: length=9  (參照kfddde[1].fgname

kfdhdb.crestmp.hi:33020874; 0x0a8: HOUR=0xd DAYS=0x1d MNTH=0x6 YEAR=0x7df (參照kfddde[1].crestmp.hi

kfdhdb.crestmp.lo:574201856;  0x0ac: USEC=0x0 MSEC=0x182SECS=0x1b MINS=0x15 (參照kfddde[1].crestmp.lo

kfdhdb.dsksize:    8189;      0x0c4: 0x00001ffd (參照kfddde[1].size

kfdhdb.f1b1locn:   0 ;        0x0d4: 0x00000000 (由于asm-disk2为非file directory文件)

改动完毕后,保存为新的文本名称为asm-disk2.txt,最后利用merge命令,写入/dev/asm-disk2磁盘头中,例如以下:

[[email protected]~]$ kfed merge /dev/asm-disk2 text=/home/oracle/asm-disk2.txt

 

来总结下利用merge修复的基本步骤。1.首先确认file directory的位置,再依据filedirectory找到dis directory的位置。2.依据disk directory找出磁盘信息,手工编辑磁盘头文件;3最后用kfed merge到相应的磁盘头中。生成磁盘头信息。

最后提一下,普通情况。file directory在磁盘组某个磁盘的au=2的位置,可是假设对磁盘组进行了添加和删除操作。就可能须要手工去查询了。

5.amdu工具使用

前面我们介绍了对磁盘头信息的修复,接下来我们介绍一个对存放在ASM里面的数据进行抽取的工具amdu。我们知道,假设asm实例是启动状态,我们能够通过asmcd或者rman命令将asm中的文件提取出来。可是假设asm无法启动的情况下,以上2个工具就无发实现了。这时候我们就能够用amdu来进行数据文件的抽取。这对于极端情况下的数据恢复是很有帮助的。

AMDU是Oracle 11g里自带的一个免费的工具。用于分析ASM磁盘组的元数据以及从不能mount的磁盘组中往外抽取数据文件,它的原理就是跳过磁盘头直接解析磁盘中的filedirectory部分的内容,然后找到文件和文件夹结构,依据数据文件号,直接将文件抽取出来。

因此,使用AMDU一般要满足下面三个情况:1.ASM实例无法启动。2.磁盘中的filedirectory信息完整;3.知道数据文件号;这样我们就能够尝试把数据文件直接抽取出来,在本地启动数据库实例,接下来我们来操作下。

1.       关闭ASM实例

[[email protected]~]$ sqlplus /nolog

SQL*Plus:Release 11.2.0.4.0 Production on Thu Jul 23 14:33:24 2015

Copyright(c) 1982, 2013, Oracle.  All rightsreserved.

SQL>conn / as sysasm

Connected.

SQL>shutdown immediate;

ASMdiskgroups dismounted

ASMinstance shutdown

因为ASM中存放有CRS相关组件,因此CRS集群也被停止,整个数据库无法訪问,例如以下

[[email protected]~]$ crs_stat -t

CRS-0184:Cannot communicate with the CRS daemon.

由于ASM实例没有启动,经常使用的asmcmd也无法訪问相关的信息,例如以下

[[email protected]~]$ asmcmd

Connectedto an idle instance.

ASMCMD>ls

ASMCMD-8102:no connection to Oracle ASM; command requires Oracle ASM to run

过去遇到这样的情况,我们仅仅能想方设法的启动ASM实例,不然就仅仅能通过备份文件恢复数据。如今我们能够尝试通过amdu工具,将数据文件直接抽取出来。

2.       利用ODU中的asmcmd工具查看数据文件号

因为ORACLE自带的ASMCMD工具无法使用,这时候我们就要借助牛人开发的ODU工具进行查看了,ODU是技术达人开发的一块收费的数据抽取工具(http://www.oracleodu.com/cn/download)。我们仅仅须要下载个试用版,用于查询下即可了。

[[email protected]~]$ tar -xvf odu_trial_413_linux_x86.tar

odu/

odu/asmdisk.txt

odu/config.txt

odu/control.txt

odu/data/

odu/odu

解压后,我门仅仅须要对asmdisk.txt这个配置文件进行下设置。仅仅须要设置磁盘号和路径,我们能够通过kfod di=all得到,例如以下;

[[email protected]]$ kfod di=all

--------------------------------------------------------------------------------

 Disk         Size Path                                     User     Group  

================================================================================

  1:       8189 Mb/dev/asm-disk1                          oracle   dba    

  2:       8189 Mb/dev/asm-disk2                          oracle   dba    

  3:        509 Mb/dev/asm-disk3                          oracle   dba    

KFOD-00313:No ASM instances available. CSS group services were successfully initilized bykgxgncin

KFOD-00311:Error scanning device /dev/asm

ORA-15059:invalid device type for ASM disk

Linux-x86_64Error: 16384: Unknown system error

Additionalinformation: 42

[[email protected]]$ more asmdisk.txt

#disk_no  disk_path       group_name meta_block_size  ausize disk_size header_offset

1   /dev/asm-disk1

2    /dev/asm-disk2

3    /dev/asm-disk3

进入odu的asmcmd工具,详细操作例如以下:

[[email protected]]$ ./odu

OracleData Unloader trial version 4.1.3

Copyright(c) 2008,2009,2010,2011 XiongJun. All rights reserved.

grp#dsk# bsize ausize disksize diskname       groupname       path

-------- ----- ------ -------- --------------- -----------------------------------------------------------

   1   0  4096  1024K    8189 DATA_0000       DATA            /dev/asm-disk1

   1   1  4096  1024K    8189 DATA_0001       DATA            /dev/asm-disk2

   2   0  4096  1024K     509 ARCH_0000       ARCH           /dev/asm-disk3

loadasm disk file ‘asmdisk.txt‘ successful

loadingdefault control file ......

 ts#  fn  rfn bsize   blocks bf offset filename

-------- ---- ----- -------- -- ------ --------------------------------------------

loadcontrol file ‘control.txt‘ successful

loadingdictionary data......done

loadingscanned data......done

ODU> asmcmd

Enteringasmcmd module.

ASMCMD>ls

Currentdirectory: <root>

DiskGroup

------------------------------------

DATA

ARCH

至此,我们就进入了ODU的ASMCMD工具中,这个工具的命令数据库自带的有所细微的差别。给演示下我们怎样利用它查询数据文件的文件号:

ASMCMD>cd+data

ASMCMD>cd ORCL

Currentdirectory: +DATA/ORCL

ASMCMD>ls

Currentdirectory: +DATA/ORCL/DATAFILE

Name                                   

----------------------------------------

SYSTEM.256.883666707                   

SYSAUX.257.883666707                   

UNDOTBS1.258.883666707                 

USERS.259.883666707                    

UNDOTBS2.267.883667019                 

ZLTOOLSTBS.273.884105179               

zltoolstbs.dbf                             =>+DATA.273.884105179

ZL9BASEITEM.274.884105185              

zl9baseitem.dbf                            =>+DATA.274.884105185

ZL9PATIENT.275.884105191               

zl9patient.dbf                             =>+DATA.275.884105191

ZL9EXPENSE.276.884105193               

zl9expense.dbf                             =>+DATA.276.884105193

ZL9MEDLST.277.884105197                

zl9medlst.dbf                              =>+DATA.277.884105197

ZL9DUEREC.278.884105203                

zl9duerec.dbf                              =>+DATA.278.884105203

ZL9CISREC.279.884105207                

zl9cisrec.dbf                              => +DATA.279.884105207

ASM实例中全部文件,都有自己的文件号,如上面每一个文件的后缀中的数字。兴许我们就依据文件号,利用amdu抽取出数据文件。

3.       利用amdu抽取数据文件

这里我们尝试控制文件文件抽取出来,让数据库可以启动到mount状态

ASMCMD>cdcontrolfile

Currentdirectory: +DATA/ORCL/CONTROLFILE

ASMCMD>ls

Currentdirectory: +DATA/ORCL/CONTROLFILE

Name                                   

----------------------------------------

Current.261.883666805                  

Current.260.883666805                  

       这里我们就看到了。控制文件的文件号是260和261。接下来通过amdu进行数据抽取

[[email protected]~]$ amdu -diskstring ‘/dev/asm*‘ -extract data.260

amdu_2015_07_23_16_15_50/

[[email protected]~]$ amdu -diskstring ‘/dev/asm*‘ -extract data.261

amdu_2015_07_23_16_16_01/

能够看到,生成了2个目录,进入当中的一个

[[email protected]~]$ cd amdu_2015_07_23_16_15_50/

[[email protected]_2015_07_23_16_15_50]$ ls

DATA_260.f  report.txt

AMDU抽取生成数据文件的格式为“磁盘组+数据文件号”,而且加后缀名为点f,如这里生成的文件就是DATA_260.f,这就是抽取的控制文件,我们能够通过mv对这些文件进行移动并重命名。移动为/u01/app/oracle/controlfile01.ctl例如以下

[[email protected]~]$mv /home/oracle/amdu_2015_07_23_16_15_50/DATA_260.f/u01/app/oracle/controlfile01.ctl

接下来我们对系统自带的pfile文件(一般在/u01/app/oracle/admin/orcl/pfile目录中)进行编写,改动里面的控制文件的路径。例如以下

control_files=("+DATA/orcl/controlfile/current.261.883666805","+DATA/orcl/controlfile/current.260.883666805")

cluster_database=true

改动为:

control_files=("/u01/app/oracle/controlfile01.ctl")

cluster_database=false

启动到mount状态

SQL>startup mount pfile=‘/u01/app/oracle/admin/orcl/pfile/init.ora‘

ORACLEinstance started.

TotalSystem Global Area  772472832 bytes

FixedSize                2257232 bytes

VariableSize                  566234800 bytes

DatabaseBuffers           201326592 bytes

RedoBuffers                    2654208 bytes

Databasemounted.

SQL>

后面我们就能够用类似的方法。通过amdu把其它剩余的全部数据文件、REDO日志文件等抽取出来,然后将控制文件里的路径作调整(能够通过重建控制文件的方式),就是一个简单的冷备恢复,把数据库脱离ASM又一次启动起来,因为篇幅限制这里就不再演示了。

6.总结

ASM作为ORACLE推崇的数据存储方式,在性能、安全、管理上都提供了极大的方便,可是因为其高密闭的封装,导致一旦出现故障。DBA对其往往束手无策。今天我们分别介绍了几个日常大家不怎么接触的数据库自带的ASM维护小工具。可以从内部深探ASM的架构。为我们在极端情况下进行一些解救性的操作提供了方法,请有兴趣的同事可以尝试学习研究,可以有效的掌握这些工具的使用。

 

參考文档:ASM tools used by Support :KFOD, KFED, AMDU (文档 ID 1485597.1)















以上是关于介绍Oracle自带的一些ASM维护工具 (kfod/kfed/amdu)的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 从ASM复制文件到文件系统

数据恢复:AMDU数据抽取恢复

ASM字节码操作 工具类与常用类 LocalVariablesSorter 类 简单介绍与使用

Oracle性能优化之性能诊断工具_超越OCP精通Oracle视频教程培训33

ASM字节码操作 工具类与常用类 asm-utils 与 asm-commons

oracle 中asm用法