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