• 介绍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得到结果例如以下:

    [oracle@rac01~]$ 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  查看磁盘组信息

    [oracle@rac01~]$ 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  查看磁盘组的组成

    [oracle@rac01~]$ 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启动的状态下訪问),我们相同先来看下帮助信息。例如以下:

    [oracle@rac01~]$ 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号数据块中,那么如今我们就以当中的一个来看一下它的磁盘头究竟存储了那些信息,例如以下:

    [oracle@rac01~]$ 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,我们能够查询下:

    磁盘头信息:

    [oracle@rac01~]$  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倒数第二个数据块信息:

    [oracle@rac01~]$  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磁盘的磁盘头信息。例如以下

    [oracle@rac01~]$ 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

    [oracle@rac01~]$  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磁盘头信息位置。例如以下

    [oracle@rac01~]$ kfed repair /dev/asm-disk1

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

    [oracle@rac01~]$ 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,例如以下:

    [oracle@rac01~]$ 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磁盘,通过例如以下查询:

    [oracle@rac01~]$  kfed read /dev/asm-disk1  |grep f1b1

    kfdhdb.f1b1locn:                      2 ; 0x0d4: 0x00000002

    [oracle@rac01~]$  kfed read /dev/asm-disk2  |grep f1b1

    kfdhdb.f1b1locn:                      0 ; 0x0d4: 0x00000000

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

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

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

    kfdhdb.f1b1locn:                      2; 0x0d4: 0x00000002

    [oracle@rac01~]$ 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条信息。

    [oracle@rac01~]$ 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磁盘了。因此我们仅仅须要查看涉及该磁盘的相关信息,例如以下:

    [oracle@rac01~]$ 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的磁盘头信息改动)

    [oracle@rac01 ~]$ 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磁盘头中,例如以下:

    [oracle@rac01~]$ 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实例

    [oracle@rac01~]$ 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集群也被停止,整个数据库无法訪问,例如以下

    [oracle@rac01~]$ crs_stat -t

    CRS-0184:Cannot communicate with the CRS daemon.

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

    [oracle@rac01~]$ 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)。我们仅仅须要下载个试用版,用于查询下即可了。

    [oracle@rac01~]$ 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得到,例如以下;

    [oracle@rac01odu]$ 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

    [oracle@rac01odu]$ 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工具,详细操作例如以下:

    [oracle@rac01odu]$ ./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进行数据抽取

    [oracle@rac01~]$ amdu -diskstring '/dev/asm*' -extract data.260

    amdu_2015_07_23_16_15_50/

    [oracle@rac01~]$ amdu -diskstring '/dev/asm*' -extract data.261

    amdu_2015_07_23_16_16_01/

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

    [oracle@rac01~]$ cd amdu_2015_07_23_16_15_50/

    [oracle@rac01amdu_2015_07_23_16_15_50]$ ls

    DATA_260.f  report.txt

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

    [oracle@rac01~]$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)

  • 相关阅读:
    Python 虚拟环境(VirtualEnv)
    python 枚举
    Python 面向对象编程
    Python 使用模块
    Python 函数
    Python dict & set
    JAVA-工具类
    09-12 练习题
    JAVA-数组
    java-语句
  • 原文地址:https://www.cnblogs.com/llguanli/p/7039600.html
Copyright © 2020-2023  润新知