在Oracle 10.2.0.5之前,ASM磁盘的头块并没有自己的备份,因此一旦头块损坏,如果没有以前kfed read备份出来的信息,也就没有办法使用kfed merge来作头块恢复,特别是如果一个磁盘组中所有的磁盘头块都出现问题(比如被人为地创建了PV),恢复ASM磁盘头块的操作就会非常麻烦。
但是从Oracle 10.2.0.5之后,ASM磁盘的头块会自动备份在另外一个块中,这实际上是Oracle 11g出现的功能,不过经过测试,在Oracle 10.2.0.5版本中,这个备份也是存在的。
正是因为存在这个备份,所以Oracle 10.2.0.5之后的kfed程序才有了新的repair命令,该命令将备份块直接覆盖到磁盘头块,完成修复工作。
在Oracle 10.2.0.4中,如果尝试执行kfed repair,则会报错说命令行参数不正确,此报错说明并不存在repair命令:
$ kfed repair
KFED-00101: LRM error [102] while parsing command line arguments
但是在Oracle 10.2.0.5中,执行kfed repair,则会说无法打开文件空,而这正说明repair命令是存在的,报错是因为还需要明确指定要修复哪块磁盘:
$ kfed repair
KFED-00303: unable to open file ''
那么这个备份块具体存在哪里呢?在Solaris下的测试,我们使用truss来进行跟踪。
$ truss -o tracedisk2.out kfed repair /asmdisks/vdisk2
在trace文件中,找到下面这段,可以明确地看到kfed程序从第510个块中读出4096字节,然后再写回到第0个块中。
stat("/asmdisks/vdisk2", 0xFFFFFD7FFFDFDB20) = 0
open("/asmdisks/vdisk2", O_RDWR) = 7
lseek(7, 0x001FE000, SEEK_SET) = 2088960 <-- 1FE is 510
read(7, "01820101FE\0\0\0\0\0\080".., 4096) = 4096 <-- read 4096 bytes
lseek(7, 0, SEEK_SET) = 0
read(7, "01820101\0\0\0\0\0\0\080".., 4096) = 4096
lseek(7, 0, SEEK_SET) = 0 <-- 0 is 0
write(7, "01820101\0\0\0\0\0\0\080".., 4096) = 4096 <-- write 4096 bytes
close(7)
同样如果是在Linux下用裸设备作为ASM磁盘,并且用strace进行repair命令的跟踪,也可以得到类似结果。
open("/dev/raw/raw3", O_RDWR) = 5
lseek(5, 2088960, SEEK_SET) = 2088960 <-- 2088960/4096=510
read(5, "\1\202\1\1\0\0\0\0\0\0\0\200evx\257\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
lseek(5, 0, SEEK_SET) = 0
read(5, "\1\202\1\1\0\0\0\0\0\0\0\200evx\257\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
lseek(5, 0, SEEK_SET) = 0
write(5, "\1\202\1\1\0\0\0\0\0\0\0\200evx\257\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
close(5) = 0
那么通过kfed命令再来验证一下这两个块是否都标志为头块。验证结果表示块类型都为DISKHEAD。
$ kfed read /asmdisks/vdisk2 blkn=0 | grep KFBTYP
kfbh.type: 1 ; 0x002: KFBTYP_DISKHEAD
$ kfed read /asmdisks/vdisk2 blkn=510 | grep KFBTYP
kfbh.type: 1 ; 0x002: KFBTYP_DISKHEAD <-- this is the backup!!
那么下一个疑问是,在11gR2以后,ASM磁盘组的AU Size可以指定不同的大小,是不是不同的AU Size下的磁盘头块备份都是在第510个块呢?还是用truss来跟踪一下,这里的vdisk3属于一个AU Size=8M的磁盘组,此时repair命令需要明确指定aus,否则会报KFED-00320错误。
truss -o tracedisk3.out kfed repair /asmdisks/vdisk3 aus=8388608
在trace文件中,可以发现已经不再是去读第510个块,而是改为读第4094个块。
stat("vdisk3", 0xFFFFFD7FFFDFDB10) = 0
open("vdisk3", O_RDWR) = 7
lseek(7, 0x00FFE000, SEEK_SET) = 16769024 <--FFE is 4094
read(7, "01820101FE07\0\0\0\0\080".., 4096) = 4096
lseek(7, 0, SEEK_SET) = 0
read(7, "01820101\0\0\0\0\0\0\080".., 4096) = 4096
lseek(7, 0, SEEK_SET) = 0
write(7, "01820101\0\0\0\0\0\0\080".., 4096) = 4096
close(7)
用kfed验证第4094个块,确实标志为DISKHEAD。
$ kfed read /asmdisks/vdisk3 blkn=4094 | grep KFBTYP
kfbh.type: 1 ; 0x002: KFBTYP_DISKHEAD
那么也就是AU 1M的磁盘组头块备份在第510个块上,而AU 8M的磁盘组头块备份在第4094个块上,备份块的存储位置有规律吗?有的,始终保存在第2个AU的倒数第2个块上。下面来验证这个观点。
对于默认的磁盘组,AU Size=1M,每个AU中可以存储256个块,块号为0-255。第1个AU存储256个块,第2个AU最后1个块号为255,倒数第2个块号是254,也就是整体的第510个块(从第1个AU的第1个块往后算起)。
$ kfed read /asmdisks/vdisk2 blkn=0 | grep ausize
kfdhdb.ausize: 1048576 ; 0x0bc: 0x00100000
$ kfed read /asmdisks/vdisk2 blkn=0 | grep blksize
kfdhdb.blksize: 4096 ; 0x0ba: 0x1000
$ let r=1048576/4096;echo $r
256
$ let r=256+255-1;echo $r
510
对于AU Size=8M的磁盘组,每个AU可以存储2048个块,块号为0-2047。第1个AU存储2048个块,第2个AU最后1个块号为2047,倒数第2个块号是2046,也就是整体的第4094个块(从第1个AU的第1个块往后算起)。
$ kfed read /asmdisks/vdisk3 blkn=0 | grep ausize
kfdhdb.ausize: 8388608 ; 0x0bc: 0x00800000
$ kfed read /asmdisks/vdisk3 blkn=0 | grep blksize
kfdhdb.blksize: 4096 ; 0x0ba: 0x1000
$ let r=8388608/4096;echo $r
2048
$ let r=2048+2047-1;echo $r
4094
对于其它AU Size磁盘组的验证,看到文章的朋友有兴趣可以自己做一下。
结论:
从Oracle 10.2.0.5开始,ASM磁盘已经开始自动将头块进行备份,备份块的位置在第2个AU的倒数第2个块上(对于默认1M的AU来说,是第510个块),如果头块损坏,可以用kfed repair命令来修复。因此对于选用ASM存储作为生产环境的用户来说,尽快升级到10.2.0.5是明智的选择。
2 Comments Add yours