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的基础应用。
前面说了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工具对其进行解读。
kfod和kfed是ASM自带的未公开的工具,kfod主要用于在系统级别对ASM信息的查看。而kfed它能够读取和改动ASM磁盘的元数据,对修复一些关键错误很实用,接下来分别介绍和演示下这两个工具。
(下面使用的环境数据库版本号都是11gr2)
我们曾经要想訪问和查询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
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操作直接恢复。相当的方便。
因为磁盘头的信息相对简单并且变化非常小,特别是同一磁盘组的磁盘,每一个磁盘头的信息差点儿一致,而当我们了解了磁盘头的信息后,一旦某个磁盘头的信息出现了问题,我们能够利用其它磁盘头信息然后通过kfed工具对其进行改动和调整,达到修复的目的。当中用得最多的是读取(Read)、修复(Repair)和合并(Merge)三个操作。
首先大家要明白一点,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
。。
。。。
。
。(下面内容略)
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的位置,在2号au
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的位置,可是假设对磁盘组进行了添加和删除操作。就可能须要手工去查询了。
前面我们介绍了对磁盘头信息的修复,接下来我们介绍一个对存放在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又一次启动起来,因为篇幅限制这里就不再演示了。
ASM作为ORACLE推崇的数据存储方式,在性能、安全、管理上都提供了极大的方便,可是因为其高密闭的封装,导致一旦出现故障。DBA对其往往束手无策。今天我们分别介绍了几个日常大家不怎么接触的数据库自带的ASM维护小工具。可以从内部深探ASM的架构。为我们在极端情况下进行一些解救性的操作提供了方法,请有兴趣的同事可以尝试学习研究,可以有效的掌握这些工具的使用。
參考文档:ASM tools used by Support :KFOD, KFED, AMDU (文档 ID 1485597.1)