Where is the backup of ASM disk header block?

在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是明智的选择。

How to use asmca to create ASM instance silently in Oracle 11gR2

对于只能登录字符界面的很多服务器而言,能够使用silent模式创建一些组件是至关重要的。本文介绍如何在字符界面下使用asmca来创建ASM实例。

测试环境:Oracle 11.2.0.3 + Oracle Restart 【关于Oracle Restat,可以参看我之前的文章-How to Use Oracle Restart in Oracle 11gR2

在没有创建ASM实例之前,Clusterware中的资源状况如下:

grid@solaris:~$ ct
--------------------------------------------------------------------------------
NAME           TARGET  STATE        SERVER                   STATE_DETAILS       
--------------------------------------------------------------------------------
Local Resources
--------------------------------------------------------------------------------
ora.LISTENER_SOLARIS.lsnr
               ONLINE  ONLINE       solaris                                      
ora.ons
               OFFLINE OFFLINE      solaris                                      
--------------------------------------------------------------------------------
Cluster Resources
--------------------------------------------------------------------------------
ora.cssd
      1        OFFLINE OFFLINE                                                   
ora.diskmon
      1        OFFLINE OFFLINE                                                   
ora.evmd
      1        ONLINE  ONLINE       solaris                                      
ora.orcl.db
      1        ONLINE  ONLINE       solaris                  Open                

通过如下命令用gird用户创建ASM实例。

asmca -silent -configureASM -sysAsmPassword oracle -asmsnmpPassword oracle -diskString '/asmdisks/vdisk*' -diskGroupName DATADG -disk '/asmdisks/vdisk1' -redundancy EXTERNAL

-silent:表示静默模式,这在字符界面中至关重要。
-configureASM:表示本命令是用于配置ASM实例,如果ASM实例不存在,则会新建。
-sysAsmPassword:sysasm权限用户的密码。
-asmsnmpPassword:asmsnmp权限用户的密码。如果用过asmca图形界面的应该记得这两个密码在图形界面中都是需要输入的。
-diskString:ASM磁盘组的磁盘发现路径。
-diskGroupName:需要新建的磁盘组名称。
-disk:ASM磁盘名称。
-redundancy:磁盘冗余方式,本例中使用了外部冗余。

会有大量的屏幕输出,但是最后显示如下行表示命令成功完成。

ASM created and started successfully.

Disk Group DATADG created successfully.

再次检查Clusterware的资源状况,可以看到已经增加了ASM资源,并且已经正常启动。

grid@solaris:~$ ct
--------------------------------------------------------------------------------
NAME           TARGET  STATE        SERVER                   STATE_DETAILS       
--------------------------------------------------------------------------------
Local Resources
--------------------------------------------------------------------------------
ora.LISTENER_SOLARIS.lsnr
               ONLINE  ONLINE       solaris                                      
ora.asm
               ONLINE  ONLINE       solaris                  Started             
ora.ons
               OFFLINE OFFLINE      solaris                                      
--------------------------------------------------------------------------------
Cluster Resources
--------------------------------------------------------------------------------
ora.cssd
      1        ONLINE  ONLINE       solaris                                      
ora.diskmon
      1        OFFLINE OFFLINE                                                   
ora.evmd
      1        ONLINE  ONLINE       solaris                                      
ora.orcl.db
      1        ONLINE  ONLINE       solaris                  Open                

查看ASM磁盘组状况。

ASMCMD> lsdg
State    Type    Rebal  Sector  Block       AU  Total_MB  Free_MB  Req_mir_free_MB  Usable_file_MB  Offline_disks  Voting_files  Name
MOUNTED  EXTERN  N         512   4096  1048576       976      917                0             917              0             N  DATADG/

接下来增加一个磁盘到该磁盘组中,同样通过asmca来完成,当然这个操作也可以用SQL*Plus中的alter diskgroup命令来完成。

asmca -silent -addDisk -diskGroupName DATADG -disk '/asmdisks/vdisk2' -sysAsmPassword oracle

同样会有大量输出,最后显示如下行表示操作完成。

Disks added successfully to disk group DATADG

再次检查ASM磁盘组状况。可以看到磁盘组容量已经扩充。

ASMCMD> lsdg
State    Type    Rebal  Sector  Block       AU  Total_MB  Free_MB  Req_mir_free_MB  Usable_file_MB  Offline_disks  Voting_files  Name
MOUNTED  EXTERN  N         512   4096  1048576      1952     1891                0            1891              0             N  DATADG/  

如果想获得asmca的帮助,可以通过以下命令。

asmca -help

How to use udev for Oracle ASM in Oracle Linux 6

大部分在网上可以找到的文档都是在RHEL5或者OEL5中设置udev,udev对于Linux而言最大的作用是防止操作系统重新启动以后,作为ASM磁盘使用的盘符发生变化。
比如说Tim Hall的文章:UDEV SCSI Rules Configuration for ASM in Oracle Linux 5
比如说Maclean的文章:利用UDEV服务解决RAC ASM存储设备名

但是在OEL6或者RHEL6中,这一切都有所变化。

主要的变化是:
1. scsi_id的命令语法发生了变化,scsi_id -g -u -s这样的命令不再有效。
2. udevtest命令已经没有了,整合到了udevadm中。

可以参考Redhat的官方文档(这个文档中本身有一些错误,在udev rules中漏了–device=,正确的方法参看下面的第3步):
Configuring persistent storage in Red Hat Enterprise Linux 6

步骤如下:
1. 编辑/etc/scsi_id.config文件,如果该文件不存在,则创建该文件,添加如下行:

options=--whitelisted --replace-whitespace

备注:在我的测试中,此步骤可以省略。

2. 获取需要绑定为ASM Disk的磁盘uuid,比如我们要使用/dev/sdc和/dev/sdd作为ASM磁盘,那么:

# scsi_id --whitelisted --replace-whitespace --device=/dev/sdc
1ATA_VBOX_HARDDISK_VB36a9e548-1838194a
# scsi_id --whitelisted --replace-whitespace --device=/dev/sdd
1ATA_VBOX_HARDDISK_VB9808fc7f-cdf35030

3. 编写udev rules文件,PROGRAM中写scsi_id命令,RESULT中写上面命令中返回的uuid,这跟OEL5中没什么区别,只是scsi_id命令的语法发生变化了。

vi /etc/udev/rules.d/99-oracle-asmdevices.rules
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/$name", RESULT=="1ATA_VBOX_HARDDISK_VB36a9e548-1838194a", NAME="asm-disk1",  OWNER="grid",  GROUP="dba", MODE="0660"
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/$name", RESULT=="1ATA_VBOX_HARDDISK_VB9808fc7f-cdf35030", NAME="asm-disk2",  OWNER="grid",  GROUP="dba", MODE="0660"

4. 用udevadm进行测试,注意udevadm命令不接受/dev/sdc这样的挂载设备名,必须是使用/sys/block/sdc这样的原始设备名。

udevadm test /sys/block/sdc
udevadm info --query=all --path=/sys/block/sdc
udevadm info --query=all --name=asm-disk1

在显示中,有类似如下输出,表示测试正确,/dev/sdc设备在udev启动以后将会绑定为/dev/asm-disk1:

udevadm_test: UDEV_LOG=6
udevadm_test: DEVPATH=/devices/pci0000:00/0000:00:0d.0/host4/target4:0:0/4:0:0:0/block/sdc
udevadm_test: MAJOR=8
udevadm_test: MINOR=32
udevadm_test: DEVNAME=/dev/asm-disk1
udevadm_test: DEVTYPE=disk
udevadm_test: ACTION=add
udevadm_test: SUBSYSTEM=block

5. 启动udev

# /sbin/start_udev

6. 检查设备是否正确绑定

# ls -l /dev/asm*
brw-rw---- 1 grid dba 8, 32 Oct 26 21:24 /dev/asm-disk1
brw-rw---- 1 grid dba 8, 48 Oct 26 21:17 /dev/asm-disk2