分享

ASM的文件管理深入解析(内含开源的ASM文件挖掘研究版程序)

 陈永正的图书馆 2016-12-29
 本帖最后由 vage 于 2012-3-31 10:07 编辑

ASM的文件管理深入解析(内含开源的ASM文件挖掘研究版程序):

(帖子太长,分三楼发出来,ASM文件挖掘程序的下载,在第二楼)

09年刚到阿里时,研究过一阵子ASM,当时还写了一个ASM文件直接读取的程序,就是本文后面所附的。算起来,这应该是国内首款这方面的程序了。但当时只发在公司内部的邮件组,一直没有时间整理出来。现在终于清闲些了,而且ASM也使用的越来越多,而且以后绝对是Oracle重点发展方向之一,所以决定将此程序整理出来,再配合些详细的介绍,希望可以提升大家对ASM的了解程度。
也是09年初,曾经和朋友一起写过一个Oracle日志解析的程序,取名为日志挖掘研究版( http://www./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分布。
创建如下表空间:
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视图。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多