【作者简介】
本人医疗行业DBA,从业7年,精通oracle底层;会文件、触发器加密的勒索恢复、asm磁盘组不能mount及各种灾难恢复,后面将利用空闲时间将自己工作中遇到的问题及整理的资料分享给更多愿意学习和提升自己的dba。
【正文】
使用FST/AT进行ASM磁盘空间管理,类似block的空间管理。每个ASM磁盘有独立的FST/AT。
1、Free Space Table(FST) and Allocation Table(AT)
1.1 fst 介绍
在进行创建文件或者文件resize过程中,需要有一个快捷入口,可以迅速的知道当前磁盘有哪些可用的(free状态的)AU,ASM Free Space Table 简称FST表就是提供一个这样的功能,通过它可以快速的知道哪些allocation table(AT表)元数据块中有空闲的AU,它存储的是一个个的AT表元数据块的号码,FST表用来加速AU的分配,避免读取已经完全被占用殆尽的AT块,造成分配空间效率的低下。
FST表从技术上说其实是属于AT表的一部分,位于AT表的块1,FST表和AT表都被称为物理元数据,它们经常位于ASM磁盘的固定的位置。
1.2 At 介绍
每一块由ASM管理的磁盘都会至少包含一个Allocation Table ,简称AT表,它是用来描述磁盘的AU分布情况的,AT表里的每一个条目都代表了磁盘上的一个AU,一旦某个AU被分配出去,AT表中此条目的内容会被更新,例如此AU属于的extent号和属于哪一个文件。
0号块为磁盘头,FST存在本AU的1号块,后面还有254个块(KFBTYP_FREESPC: kfdfsb.max,kfdfse[i].fse),也就AT块,一个FST可以管理254个AT块。一个AT块可以管理448个AU块(KFBTYP_ALLOCTBL: kfdatb.shrink,AT条目:kfdate[i]),每个AT条目包括物理扩展号和文件号,以及状态,每个AT条目对应AU号(kfdate[i])。
2、Free Space Table(FST) 和 Allocation Table(AT) 存储位置
从磁盘头的信息可以发现FST起始位置为1号块,AT起始位置为2号块,通过kfed工具可以查看磁盘头信息;
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blkn=0|grep -E "aus|fstlocn|altlocn" //disk header定位
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blkn=1 aus=1048576|more //fst
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blkn=2 aus=1048576|more //at
其中kfdhdb.fstlocn的值代表了FST块位于磁盘头所在au 0的第2个块。同理看kfdhdb.altlocn的值代表AT位于au 0的第3个块。
3、Free Space Table(FST) 和 Allocation Table(AT) 元数据说明
//FST补充:
kfdfsb.aunum: 0 ; 0x000: 0x00000000 --对于这个FST块,第一个AT表元数据位于AU0
kfdfsb.max: 254 ; 0x004: 0x00fe --这个FST块最大数量的FST条目可以达到254个,虽然上面kfed的输出中kfdfse[i]的编号到了4039,也就是有4039+1=4040个条目,但是有效条目只有254个。
//AT补充:
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blkn=2 aus=1048576|more
kfdatb.aunum: 0 ; 0x000: 0x00000000 --kfdatb.aunum=0 意味着AU0是这个AT块所描述的第一个AU(也就是说是某个AT块记录AU使用的起点)
kfdatb.shrink: 448 ; 0x004: 0x01c0 --kfdatb.shrink=448 意味着这个AT 块可以包含448个AU的分配信息。因此不难猜测,在下一个AT块,kfdatb.aunum的值应该为448(AU编号是从0号开始),它包含的是AU 448到AU (448+448)的分配信息,我们通过kfed来证明一下:
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blkn=3 aus=1048576|grep kfdatb.aunum
kfdatb.aunum: 448 ; 0x000: 0x000001c0
同样,第三个AT块(AU的第四个块)应该显示kfdatb.aunum=896:
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blkn=4 aus=1048576|grep kfdatb.aunum
kfdatb.aunum: 896 ; 0x000: 0x00000380
--对于已经分配出去的AU,flag V=1,否则,flag V=0,AU还没有分配给具体的文件或者已经释放掉的AU。
kfdate[0].discriminator: 1 ; 0x028: 0x00000001
kfdate[0].allo.lo: 0 ; 0x028: XNUM=0x0
kfdate[0].allo.hi: 8388608 ; 0x02c: V=1 I=0 H=0 FNUM=0x0
kfdate[1].discriminator: 1 ; 0x030: 0x00000001
kfdate[1].allo.lo: 0 ; 0x030: XNUM=0x0
kfdate[1].allo.hi: 8388608 ; 0x034: V=1 I=0 H=0 FNUM=0x0
4、Allocation table(AT) 分配条目
//这里我读取DATA磁盘组下的两个设备/dev/asmdata1和asmdata2,它的AU大小是1M,我从这个磁盘组中读取259号文件的空间分布信息(+DATA/orcl/datafile/users.259.1127666971),下面我将259转换为16进制,然后用以下命令扫描看在哪个AT块上进行了记录,然后再通过和sql查询x$kffxp.pxn_kffxp字段的方式进行对比看是否一致;
for ((j=0;j<255;j++));do
content=`kfed read dev/asmdata2 aun=0 blknum=$j aus=1048576|grep -i "FNUM=0x103"`
if [ "$content" != "" ];then
echo "blknum="$j "cntent="$content
fi
done;
//通过命令扫描,可以发现file 259的磁盘分布分别在如下位置:
/dev/asmdata1 blknum=3 dir=kfdate[246]、kfdate[247]、kfdate[248]
/dev/asmdata2 blknum=3 dir=kfdate[244]、kfdate[245]、kfdate[246]
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blknum=3 aus=1048576|egrep -i "kfdatb.aunum"
kfdatb.aunum: 448 ; 0x000: 0x000001c0
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blknum=3 aus=1048576|egrep -i "FNUM=0x103" -B 2
kfdate[246].discriminator: 1 ; 0x7d8: 0x00000001
kfdate[246].allo.lo: 1 ; 0x7d8: XNUM=0x1
kfdate[246].allo.hi: 8388867 ; 0x7dc: V=1 I=0 H=0 FNUM=0x103
kfdate[247].discriminator: 1 ; 0x7e0: 0x00000001
kfdate[247].allo.lo: 3 ; 0x7e0: XNUM=0x3
kfdate[247].allo.hi: 8388867 ; 0x7e4: V=1 I=0 H=0 FNUM=0x103
kfdate[248].discriminator: 1 ; 0x7e8: 0x00000001
kfdate[248].allo.lo: 5 ; 0x7e8: XNUM=0x5
kfdate[248].allo.hi: 8388867 ; 0x7ec: V=1 I=0 H=0 FNUM=0x103
[grid@hisdb01 ~]$ kfed read dev/asmdata2 aun=0 blknum=3 aus=1048576|egrep -i "kfdatb.aunum"
kfdatb.aunum: 448 ; 0x000: 0x000001c0
[grid@hisdb01 ~]$ kfed read dev/asmdata2 aun=0 blknum=3 aus=1048576|egrep -i "FNUM=0x103" -B 2
kfdate[244].discriminator: 1 ; 0x7c8: 0x00000001
kfdate[244].allo.lo: 0 ; 0x7c8: XNUM=0x0
kfdate[244].allo.hi: 8388867 ; 0x7cc: V=1 I=0 H=0 FNUM=0x103
kfdate[245].discriminator: 1 ; 0x7d0: 0x00000001
kfdate[245].allo.lo: 2 ; 0x7d0: XNUM=0x2
kfdate[245].allo.hi: 8388867 ; 0x7d4: V=1 I=0 H=0 FNUM=0x103
kfdate[246].discriminator: 1 ; 0x7d8: 0x00000001
kfdate[246].allo.lo: 4 ; 0x7d8: XNUM=0x4
kfdate[246].allo.hi: 8388867 ; 0x7dc: V=1 I=0 H=0 FNUM=0x103
注:kfdate[i].allo.lo的值代表了文件的物理的extent号,即视图X$KFFXP的PXN_KFFXP字段。
上面摘录的信息显示,ASM的259号文件 (十六进制FNUM=0x103转换后)在AT表中占用了一些条目,从/dev/asmdata1 kfdate[246] 到 kfdate[248],共3个AU
从/dev/asmdata2 kfdate[244] 到 kfdate[246],共3个AU
一共包含了6个AU,AU的绝对AU号计算方式为kfdate[i] + offset (kfdatb.aunum=448),也就是说【246+448=694, 247+448=695, 248+448=696】,【244+448=692, 245+448=693, 246+448=694】,可以通过查询X$KFFXP视图得到证实:
select AU_KFFXP from X$KFFXP
where GROUP_KFFXP=1 -- disk group 1
and NUMBER_KFFXP=259 order by 1 -- file 259;
注:视图X$KFFXP记录的信息,准确的说是extent的信息而非AU,当文件的extent数量大于20000的时候,AU_KFFXP字段的值仅仅代表了这个extent的起始AU号。
例如下面的语句查看了496号文件的前几个extent和大于20000以后的4个extent,前几个的AU_KFFXP(Allocation unit)值是连续的,大于20000的Allocation unit值是跳跃的,这是因为AU_KFFXP的值只代表了这个extent起始的AU号。SIZE_KFFXP的值代表了这个extent是由几个AU组成的。
select XNUM_KFFXP "Virtual extent", PXN_KFFXP "Physical extent", LXN_KFFXP "Extent copy", DISK_KFFXP "Disk", AU_KFFXP "Allocation unit",SIZE_KFFXP
from X$KFFXP
where GROUP_KFFXP=1 and NUMBER_KFFXP=496 and SIZE_KFFXP=1 and DISK_KFFXP=2
and rownum<10
union all
select XNUM_KFFXP "Virtual extent", PXN_KFFXP "Physical extent", LXN_KFFXP "Extent copy", DISK_KFFXP "Disk", AU_KFFXP "Allocation unit",SIZE_KFFXP
from X$KFFXP
where GROUP_KFFXP=1 and NUMBER_KFFXP=496 and AU_KFFXP>384224 and DISK_KFFXP=2
;
Virtual extent Physical extent Extent copy Disk Allocation unit SIZE_KFFXP
-------------- --------------- ----------- ---------- --------------- ----------
2 5 1 2 380130 1
6 12 0 2 380131 1
16 32 0 2 380132 1
24 49 1 2 380133 1
26 52 0 2 380134 1
29 59 1 2 380135 1
36 72 0 2 380136 1
46 92 0 2 380137 1
50 101 1 2 380138 1
21150 42300 0 2 384228 4
21156 42313 1 2 384232 4
21160 42320 0 2 384236 4
21170 42340 0 2 384240 4
通过在AT表中搜索某个虚拟extent号大于20000的extent也可以看出,它是由4个AU组成的。
for (( i=0; i<256; i++ ))
do
kfed read dev/mmm/path-102.321.01.fioa blkn=$i|grep 45340
done
kfdate[388].allo.lo: 45340 ; 0xc48: XNUM=0xb11c
kfdate[389].allo.lo: 45340 ; 0xc50: XNUM=0xb11c
kfdate[390].allo.lo: 45340 ; 0xc58: XNUM=0xb11c
kfdate[391].allo.lo: 45340 ; 0xc60: XNUM=0xb11c
5、Allocation table(AT) free space
[grid@hisdb01 ~]$ kfed read dev/asmdata2 aun=0 blknum=5 aus=1048576|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 3 ; 0x002: KFBTYP_ALLOCTBL
kfbh.datfmt: 2 ; 0x003: 0x02
kfbh.block.blk: 5 ; 0x004: blk=5
...
kfdate[246].discriminator: 1 ; 0x7d8: 0x00000001
kfdate[246].allo.lo: 347 ; 0x7d8: XNUM=0x15b
kfdate[246].allo.hi: 8388866 ; 0x7dc: V=1 I=0 H=0 FNUM=0x102
kfdate[247].discriminator: 1 ; 0x7e0: 0x00000001
kfdate[247].allo.lo: 349 ; 0x7e0: XNUM=0x15d
kfdate[247].allo.hi: 8388866 ; 0x7e4: V=1 I=0 H=0 FNUM=0x102 --换算成10进制为258号文件,通过查看是undo表空间
kfdate[248].discriminator: 0 ; 0x7e8: 0x00000000
kfdate[248].free.lo.next: 20 ; 0x7e8: 0x0014
kfdate[248].free.lo.prev: 20 ; 0x7ea: 0x0014
kfdate[248].free.hi: 3 ; 0x7ec: V=0 ASZM=0x3
kfdate[249].discriminator: 0 ; 0x7f0: 0x00000000
kfdate[249].free.lo.next: 0 ; 0x7f0: 0x0000
kfdate[249].free.lo.prev: 0 ; 0x7f2: 0x0000
kfdate[249].free.hi: 0 ; 0x7f4: V=0 ASZM=0x0
在上面kfed的输出中,我们可以看到kfdate[248]及之后的是free的AU,因为标志V=0,后面的输出被我人为的截断掉了,其实这个AT块中还有很多没有被分配出去的free的AU。
6、the stride
每一个AT块(4K)可以描述448个AU(kfed输出的kfdatb.shrink值表明了这一点),每一个AT表有254个块(Free Space Table块中的 kfdfsb.max的值表明了这一点)。这意味着一个AT表可以用来描述254*448= 113792个AU。这在ASM里被称为一个stride,一个stride可以描述的AU在ASM的磁盘头的kfdhdb.mfact部分看到:
[grid@hisdb01 ~]$ kfed read dev/asmdata1 aun=0 blkn=0|grep mfact
kfdhdb.mfact: 113792 ; 0x0c0: 0x0001bc80
在我们例子中,AU的size是1M,AU0可以装载256个元数据块,块0是磁盘头块,块1是Free Space Table,剩余254个块就是作为AT表的块。
假如AU的size是4M(Exadata的默认值),一个stride能够容纳的AU就会是454272或者说是454272*4= 1817088M,越大的AU size,stride也可以变得更大。
//如下查询的是4M的AU大小
[grid@hisdb01 ~]$ kfed read dev/asmdata6 aun=0 blknum=0 aus=4194304|grep mfact
kfdhdb.mfact: 454272 ; 0x0c0: 0x0006ee80
7、Free Space Table(FST) 有多少?
大的ASM磁盘可能会有可能超过1个stride,ASM磁盘头的kfdbdb.mfact显示了stride的大小(单位为AU),每一个stride有它自己的物理元数据,这意味着会有它自己的FST表。第二个stride的物理元数据位于这个stride的第一个AU,我们通过kfed来查看下:
[grid@hisdb01 ~]$ kfed read /dev/asmdata1 aun=0 blkn=0|grep mfact
kfdhdb.mfact: 113792 ; 0x0c0: 0x0001bc80
以上显示了stride的大小为113792个AU,由于AU是从0开始编号,因此第一个stride最后的AU号是AU 113791,我们可以推断出第二个stride的FST位置是,AU 113792的第一个块;
[grid@hisdb01 ~]$ kfed read /dev/asmdata1 aun=113792 blkn=1 | grep type
kfbh.type: 2 ; 0x002: KFBTYP_FREESPC
如预期,我们在AU 113792上有另一个FST表,如果我们还有其他的stride,同样会在stride的开始AU处有FST表。如下面所示,一个大的ASM磁盘,会有数个stride,这里展示了在第三个stride的开始处的FST表:
[grid@hisdb01 ~]$ kfed read /dev/asmdata1 aun=227584 blkn=1 | grep type
kfbh.type: 2 ; 0x002: KFBTYP_FREESPC
总结:一般FST表位于每一个ASM磁盘的AU0的块1,如果磁盘比较大,就会有不止一个stride,每一个stride都会有它自己的FST表。
8、Allocation Tables 有多少?
大的ASM磁盘stride的数量会不止一个,每一个stride都会有它自己的物理元数据,也就是会有它自己的AT表。(和前面的FST一样)
例如,我们找一个大的磁盘,看下第二个stride的物理元数据,它同样是位于这个stride的第一个AU中,我们来看下:
[grid@hisdb01 ~]$ kfed read /dev/asmdata1 aun=0 blkn=0|grep mfact
kfdhdb.mfact: 113792 ; 0x0c0: 0x0001bc80
上面显示了第一个stride包含了113792 AU,可以推算出第二个stride位于第113792 AU中(注意AU号是从0号开始计算的),AT表位于这个AU中的第2-255个块。
[grid@hisdb01 ~]$ kfed read /dev/asmdata1 aun=113792 blkn=2|grep type
kfbh.type: 3 ; 0x002: KFBTYP_ALLOCTBL
...
[grid@hisdb01 ~]$ kfed read /dev/asmdata1 aun=113792 blkn=255|grep type
kfbh.type: 3 ; 0x002: KFBTYP_ALLOCTBL
跟我们预测的一样,我们有第二个AT在第113792 AU中,继续,如果有第三个stride,那么AT同样位于stride的开始AU处。
[grid@hisdb01 ~]$ kfed read /dev/asmdata1 aun=227584 blkn=2|grep type
kfbh.type: 3 ; 0x002: KFBTYP_ALLOCTBL
总结:每一个ASM磁盘可能会包含不止一个AT表,AT表描述了磁盘的AU分配情况,AT表中的每一个条目代表了磁盘上的一个AU,如果磁盘比较大,可以有不止一个stride,每一个stride都会有它自己的AT表。