ASM的文件管理深入解析(内含开源的ASM文件挖掘研究版程序): (帖子太长,分三楼发出来,ASM文件挖掘程序的下载,在第二楼) 09年刚到阿里时,研究过一阵子ASM,当时还写了一个ASM文件直接读取的程序,就是本文后面所附的。算起来,这应该是国内首款这方面的程序了。但当时只发在公司内部的邮件组,一直没有时间整理出来。现在终于清闲些了,而且ASM也使用的越来越多,而且以后绝对是Oracle重点发展方向之一,所以决定将此程序整理出来,再配合些详细的介绍,希望可以提升大家对ASM的了解程度。 也是09年初,曾经和朋友一起写过一个Oracle日志解析的程序,取名为日志挖掘研究版( http://www.itpub.net/thread-1160446-1-1.html,算下来,都已经三年了,时间过的好快啊)。这个ASM直接读取程序,我也决定命令为“ASM文件挖掘研究版”,它还并不完善,只是给有需要的人提供一个思路。如果你不懂编号也没关系,本文的重点,除这个程序外,更多的是介绍ASM文件管理的原理。 “ASM文件挖掘研究版”远没有原来的“日志挖掘研究版复杂,也只花了很短时间,去掉一些调试性的注释只有不到300行代码。 好了,闲言少叙,准备好了吗,开始我们的ASM探秘之旅吧。
第一章 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。 1号文件总是开始在0号磁盘2号AU,记住这个位置:0号盘2号AU。这是ASM中定位文件的起点,它的作用,有点相当于磁盘上的引导区,在电脑开机后负责将OS启动起来。 1号文件在最少情况下,至少有两个AU。上面我们提到过了,在1号文件中,每个文件占用一个元数据块,存放自身的空间分布信息。每个元数据块大小是4K,一个AU是1M,哪么,每个AU中,可以存储256个文件的空间分布信息。这其中,0号盘2号AU中,全是元文件的信息。再具体一点,0号盘2号AU,第一个元数据块被系统占用,从第二个块开始,到255为止,共255个元数据块,对应索引号1至255的文件。其实,也就是全部的元文件了。也就是说0号盘2号AU,保存了全部元文件的空间分布信息。 1号文件的第二个AU,从第一个块开始,保存256号文件。第二个块对应257号文件,等等。 每次从ASM中读数据时,Oracle都要先读到1号文件,从中找出要读的目标文件在磁盘上的分布位置,然后再去读取相应的文件的数据。 不用太多文字了,文字不是最直接的表达方式,还是换成图形吧。
图1 这张图假设某一DiskGroup中有0到N个磁盘。再看下图:
图2 我们把0号盘,2号AU单独拿出来,放大显示。0号盘2号AU,是1号文件第一个AU,共有256个元数据块,编号0至255,0号块留用。1至255号块分别保存了1号文件自身和2、3等等直到255号文件的AU分布信息。 哪下面,如果我想知道某一个文件的AU分布,如何查看呢?
第 二 章 kfed
1、链接kfed 查看ASM磁盘的信息,可以使用KFED,在非Windows操作系统下,kfed已经编译过了,只要链接一下,就可以使用了,步骤如下: (1)、找到ins_rdbms.mk所在路径,并进入。此步骤不再列出。 (2)、执行如下命令,即可链接kfed。 make -f ins_rdbms.mk ikfed 2、在ASM中确定磁盘 : SQL> select group_number,name from v$asm_diskgroup; GROUP_NUMBER NAME ------------ ------------------------------ 1 DG1 我目前只有一个DG,名字是DG1,GROUP_NUMBER为1。 SQL> select group_number,disk_number,path from v$asm_disk; GROUP_NUMBER DISK_NUMBER PATH ------------ ----------- -------------------- 1 0 ORCL:VOL1 1 1 ORCL:VOL2 目前,我DG中,有两个磁盘。但这两个磁盘分别是谁,从ASM的视图中,还看不出来。不过,可以分析一下得出,/dev/sda这个盘,是系统留用的,sdb、sdc很有可能是ASM的VOL1、VOL2。那么,如何确认一下呢?这里,我也没有什么好方法,我们这样: [root@red1 dev]# dd if=/dev/sdb bs=1 count=45|hexdump -c|more 45+0 records in 45+0 records out 0000000 001 202 001 001 \0 \0 \0 \0 \0 \0 \0 200 , , m 0000010 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 0000020 O R C L D I S K V O L 1 \0 000002d 我dd命令,将/dev/sdb的前45个字节输出,其中,我们可以看到O R C L D I S K V O L 1。那么,/dev/sdb就对应VOL1了。 使用同样的方法,可以确定sdc是VOL2。还可以确定,磁盘没有分区: [root@red1 dev]# dd if=/dev/sdb1 bs=1 count=45|hexdump -c dd: opening `/dev/sdb1': No such file or directory 不存在/dev/sdb1这样的设备。 这种确定方法确实麻烦了一些,大家如果知道有什么简单方法可以补充。 好,我们已经确定,/dev/sdb对应VOL1,是磁盘0,/dev/sdc对应VOL2,是磁盘1。在我们使用kfed时,还用不到这个,如果用程序直接读取ASM文件的话,就需要用到这个信息了。 3、使用Kfed 我们使用Kfed直接读取0号磁盘,2号AU,1号元数据块吧。 0号元数据块是1号文件自身留作文件头的。1号元数据块呢,是1号文件的AU分布,2号元数据块,是2号文件的AU分布。等等。下面,我们用Kfed读取下1号元数据块。 [oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=2 blkn=1|more kfbh.endian: 1 ; 0x000: 0x01 kfbh.hard: 130 ; 0x001: 0x82 kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR kfbh.datfmt: 1 ; 0x003: 0x01 kfbh.block.blk: 1 ; 0x004: T=0 NUMB=0x1 kfbh.block.obj: 1 ; 0x008: TYPE=0x0 NUMB=0x1 kfbh.check: 4143342569 ; 0x00c: 0xf6f663e9 kfbh.fcn.base: 268 ; 0x010: 0x0000010c kfbh.fcn.wrap: 0 ; 0x014: 0x00000000 ………………………………………………………………………… 等等 Kfed可以帮我们列出很多信息,有了这些,ASM的大部分秘密将被揭开。kfed的信息是这样看的,比如: kfbh.endian: 1 ; 0x000: 0x01 kfbh.endian是C语言的结构(struct)中的域。 1 ; 0x000: 0x01 :kfbh.endian的十进值为1,0x000是指它开始自第0个字节处,最后的0x01是十六进制值形式。 此域的意义是主机的大小端。0是大端,1是小端。此处值为1,说明主机是小端。 其他的这里就不再一一列出了,对其中的每个域,我后面有详细的说明。下面,只说相关的,在Kfed中找到如下信息: kfffde[0].xptr.au: 2 ; 0x4a0: 0x00000002 kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000 kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 kfffde[0].xptr.chk: 40 ; 0x4a7: 0x28 kfffde[1].xptr.au: 27 ; 0x4a8: 0x0000001b kfffde[1].xptr.disk: 0 ; 0x4ac: 0x0000 kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0 kfffde[1].xptr.chk: 49 ; 0x4af: 0x31 kfffde[2].xptr.au: 4294967295 ; 0x4b0: 0xffffffff kfffde[2].xptr.disk: 65535 ; 0x4b4: 0xffff kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0 kfffde[2].xptr.chk: 42 ; 0x4b7: 0x2a kfffde[3].xptr.au: 4294967295 ; 0x4b8: 0xffffffff kfffde[3].xptr.disk: 65535 ; 0x4bc: 0xffff kfffde[3].xptr.flags: 0 ; 0x4be: L=0 E=0 D=0 C=0 S=0 kfffde[3].xptr.chk: 42 ; 0x4bf: 0x2a ……………… 如果你对C语言熟一点,我们会更容易描述这段信息,如果不太熟又想深入了解,可以回去翻翻谭浩强C语言书中结构体哪一部分,很简单的。kfffde,是结构数组。kfffde[0]的数据元素,存放了1号文件第一个AU的位置。kfffde[1]存放了1号文件第二个AU位置,等等,依次类推。我们来看一下上面的信息: kfffde[0].xptr.au: 2 ; 0x4a0: 0x00000002 :2号AU kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000 :0号磁盘 :上两个信息合起来,0号盘2号AU,这就是1号文件第一个AU的位置 kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 :标志位 kfffde[0].xptr.chk: 40 ; 0x4a7: 0x28 : 校验码 通过上面kfffde[0]中的信息,我们可以知道,1号文件的第一个AU,位置在0号盘2号AU处。再看kfffde[1],它对应1号文件第二个AU,位置在0号盘27号AU。再往下看kfffde[3],AU编号4294967295,磁盘编号65535。这说明1号文件还没有第三个AU。 通过上面的信息,我们可以得到,1号文件共有两个AU,分别在0号盘2号AU、0号盘27号AU。 再来一张图,帮助理解:
图3 4、读取其他文件:读取元文件 再来一个例子,假设我们想要访问3号文件,如何找出3号文件的AU都在哪里分布呢? 根据我们刚才所讲的,3号文件的AU分布,在(0号盘,2号AU,3号块)中,使用Kfed读取它: [oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=2 blkn=3|more ………………………… kfffde[0].xptr.au: 3 ; 0x4a0: 0x00000003 kfffde[0].xptr.disk: 1 ; 0x4a4: 0x0001 kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 kfffde[0].xptr.chk: 40 ; 0x4a7: 0x28 kfffde[1].xptr.au: 3 ; 0x4a8: 0x00000003 kfffde[1].xptr.disk: 0 ; 0x4ac: 0x0000 kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0 kfffde[1].xptr.chk: 41 ; 0x4af: 0x29 kfffde[2].xptr.au: 4 ; 0x4b0: 0x00000004 kfffde[2].xptr.disk: 1 ; 0x4b4: 0x0001 kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0 kfffde[2].xptr.chk: 47 ; 0x4b7: 0x2f kfffde[3].xptr.au: 4 ; 0x4b8: 0x00000004 kfffde[3].xptr.disk: 0 ; 0x4bc: 0x0000 kfffde[3].xptr.flags: 0 ; 0x4be: L=0 E=0 D=0 C=0 S=0 kfffde[3].xptr.chk: 46 ; 0x4bf: 0x2e ……………………………………………… 根据我们前面我讲的,解读这些信息是很容易的。3号文件的AU有:(1号盘3号AU)、(0号盘3号AU)、(1号盘4号AU)、(0号盘4号AU)、…………。 还是来看张图吧,更加清楚些:
图4 5、读取数据文件 我先在ASM中新建一个数据文件,然后,我们再来查看它的AU分布。 QQ买号平台创建如下表空间: create tablespace tbs_tst01 datafile '+DG1/data/tbs_tst01_00.dbf' size 10M autoextend off; 我们创建了一个10M大的数据文件,也就是说,它会有10个AU。如下查询一下它在ASM中的文件索引号: (在ASM实例中执行如下语句:) SQL> select name,file_number from v$asm_alias where name like 'tbs_tst01%'; NAME FILE_NUMBER ------------------------------------------------ ----------- tbs_tst01_00.dbf 257 FILE_NUMBER列也是文件号,我们一般称它为ASM文件索引号,在这里 tbs_tst01_00.dbf的索引号是 257。 1号文件的第一个AU(0号盘2号AU)中,只能保存1至255号文件的。从256号文件开始,AU的分布信息保存在1号文件第二个AU中,也就是(0号盘,27号AU)。其中第一个块(0号块),对应256号文件。1号块对应257号文件,等等,依此类推。 照惯例,我们先用Kfed读取一下0号盘27号AU的1号块,查看一下257号文件的AU分布: [oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=27 blkn=1|more ………………………………………… kfffde[0].xptr.au: 278 ; 0x4a0: 0x00000116 kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000 kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 kfffde[0].xptr.chk: 61 ; 0x4a7: 0x3d kfffde[1].xptr.au: 277 ; 0x4a8: 0x00000115 kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001 kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0 kfffde[1].xptr.chk: 63 ; 0x4af: 0x3f kfffde[2].xptr.au: 279 ; 0x4b0: 0x00000117 kfffde[2].xptr.disk: 0 ; 0x4b4: 0x0000 kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0 kfffde[2].xptr.chk: 60 ; 0x4b7: 0x3c ………………………………………… ………………………………………… ………………………………………… kfffde[10].xptr.au: 283 ; 0x4f0: 0x0000011b kfffde[10].xptr.disk: 0 ; 0x4f4: 0x0000 kfffde[10].xptr.flags: 0 ; 0x4f6: L=0 E=0 D=0 C=0 S=0 kfffde[10].xptr.chk: 48 ; 0x4f7: 0x30 kfffde[11].xptr.au: 4294967295 ; 0x4f8: 0xffffffff kfffde[11].xptr.disk: 65535 ; 0x4fc: 0xffff kfffde[11].xptr.flags: 0 ; 0x4fe: L=0 E=0 D=0 C=0 S=0 kfffde[11].xptr.chk: 42 ; 0x4ff: 0x2a 257号文件一共10个AU,所以,kfffde[11]中的AU位置和磁盘位置是0xffffffff、0xffff。但kfffde[10]还有是明确的值的。257号文件的10号AU位置:0号磁盘283号AU,这其实是257的第11个AU。 tbs_tst01表空间使用的是“系统管理区大小”,也就是说区大小有64K、1M、8M等多种选择。但是无论区大小,每个ASM中的文件,比原大小总会多出一个AU。就像这里的257号文件,原大小是10M,但实际是11M,共11个AU。 再来一张图吧,有图清楚些:
图5
图6 上面图5和图6,具体描述了在ASM中读取257号文件的步骤。在这里,257号文件创建大小是10M,实际在ASM中大小为11M,共11个AU。这11个AU的信息,都在0号盘、27号AU、1号块中。假设有一个非常大的文件,AU数也非常多,一个块中存不完,Oracle是如何处理的呢?下面,我们继续。 6、读取特别大的文件:间接AU 创建一个稍大一点的数据文件,比如200M: create tablespace tbs_tst02 datafile '+DG1/data/tbs_tst02_00.dbf' size 200M autoextend off; 根据我们前面所讲的,200M的数据文件,在ASM中实际将占用201M空间(201个AU)。下面,我们查找一下此文件的AU分布。首先在ASM中执行如下命令: SQL> select name,file_number from v$asm_alias where name like 'tbs_tst02%'; NAME FILE_NUMBER ------------------------------------------------ ----------- tbs_tst02_00.dbf 258 确定一下,tbs_tst02_00.dbf的文件号是258。它的AU分布信息,应该在1号文件的第二个AU的第3个块(2号块)中,老规距,先用Kfed读取1号文件第二个AU第3个块,也就是0号盘、27号AU、2号块: [oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=27 blkn=2|more ……………………………………………………………… kfffde[0].xptr.au: 282 ; 0x4a0: 0x0000011a kfffde[0].xptr.disk: 1 ; 0x4a4: 0x0001 kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 kfffde[0].xptr.chk: 48 ; 0x4a7: 0x30 kfffde[1].xptr.au: 284 ; 0x4a8: 0x0000011c kfffde[1].xptr.disk: 0 ; 0x4ac: 0x0000 kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0 kfffde[1].xptr.chk: 55 ; 0x4af: 0x37 ……………………………………………………………… 这些信息我们都熟悉了,是说明258号文件的AU分布,第一个AU在1号盘、282号AU处。第二个AU是0号盘、284号AU。等等。一直向下翻页,你会发现在kfffde[61]处,AU信息和Disk信息就已经没有了。kfffde[60]是最后一个有效AU,位置是0号盘、314号AU处: ……………………………………………………………… kfffde[60].xptr.au: 314 ; 0x680: 0x0000013a kfffde[60].xptr.disk: 0 ; 0x684: 0x0000 kfffde[60].xptr.flags: 0 ; 0x686: L=0 E=0 D=0 C=0 S=0 kfffde[60].xptr.chk: 17 ; 0x687: 0x11 kfffde[61].xptr.au: 4294967295 ; 0x688: 0xffffffff kfffde[61].xptr.disk: 65535 ; 0x68c: 0xffff kfffde[61].xptr.flags: 0 ; 0x68e: L=0 E=0 D=0 C=0 S=0 kfffde[61].xptr.chk: 42 ; 0x68f: 0x2a ……………………………………………………………… 其实,kfffde[60]已经不是258号文件实际存放数据的AU了,直到kfffde[59]还是。也就是说kfffde[0]到kfffde[59],第258号文件的前60个AU的位置信息(也就是前60M了),保存在此处。258号文件共201个AU呢,后面141个AU的位置信息在哪儿呢?就在kfffde[60]对应的,0号盘、314号AU中。 再来读取一下它:0号盘、314号AU。 [oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=314 blkn=0|more ……………………………………………………………… kfbh.block.obj: 258 ; 0x008: TYPE=0x0 NUMB=0x102 ……………………………………………………………… kffixe[0].xptr.au: 312 ; 0x00c: 0x00000138 kffixe[0].xptr.disk: 1 ; 0x010: 0x0001 kffixe[0].xptr.flags: 0 ; 0x012: L=0 E=0 D=0 C=0 S=0 kffixe[0].xptr.chk: 18 ; 0x013: 0x12 kffixe[1].xptr.au: 315 ; 0x014: 0x0000013b kffixe[1].xptr.disk: 0 ; 0x018: 0x0000 kffixe[1].xptr.flags: 0 ; 0x01a: L=0 E=0 D=0 C=0 S=0 kffixe[1].xptr.chk: 16 ; 0x01b: 0x10 kffixe[2].xptr.au: 313 ; 0x01c: 0x00000139 kffixe[2].xptr.disk: 1 ; 0x020: 0x0001 kffixe[2].xptr.flags: 0 ; 0x022: L=0 E=0 D=0 C=0 S=0 kffixe[2].xptr.chk: 19 ; 0x023: 0x13 ……………………………………………………………… 我多显示了一个域的信息:kfbh.block.obj,它代表此数据块属于哪个文件,此处的值为258,代表此数据块、此AU属于258号文件。 kffixe[0]是258号文件的第61个AU,它的位置是1号盘312号AU。注意,它就是一个间接AU。后面的kffixe[1]、kffixe[2],……,等等也都是间接AU了。 好,258号文件AU分布的查找过程,我用三幅图总结:
图7
图8
图9 ASM文件管理模式到这里就差不多了。我们使用Kfed,直接读取磁盘,描述了查找、定位文件AU分布的方式。如果只是想看看某个文件的AU分布,当然不用每次都使用Kfed,我们可以在ASM实例中,查询X$KFFXP视图。