Oracle Datafiles & Block Device & Parted & Udev

需求:
1. 使用裸设备作为Oracle数据文件,而且要跳过操作系统或者其它软件提供的卷管理(比如Linux下的LVM)。
2. 由于small datafile限制,有大量磁盘分区需要创建。

以下测试环境操作系统为CentOS 6.0,如果你的操作是RHEL6或者OEL6,也同样适用,如果是RHEL5或者OEL5,那么udev部分的命令是不相同的。但是只需要在操作系统中man udev,查看一下相应的语法即可,思路是相同的。

解决方案:
1. 使用parted命令,脚本式创建多个分区,使用gpt类型分区表,这样可以创建大量primary分区,而如果使用msdos分区,则必须要要创建extend分区,然后再创建logical分区,这样在后面的udev规则文件中,还需要将extend分区排除出去,比较麻烦。

在我的测试环境中,对于/dev/sdc磁盘进行操作,分了11个分区,每个50M。

parted -s /dev/sdc mklabel gpt 
parted -s /dev/sdc unit MB mkpart primary 1 50 
parted -s /dev/sdc unit MB mkpart primary 50 100 
parted -s /dev/sdc unit MB mkpart primary 100 150 
parted -s /dev/sdc unit MB mkpart primary 150 200 
parted -s /dev/sdc unit MB mkpart primary 250 300 
parted -s /dev/sdc unit MB mkpart primary 300 350 
parted -s /dev/sdc unit MB mkpart primary 350 400 
parted -s /dev/sdc unit MB mkpart primary 400 450 
parted -s /dev/sdc unit MB mkpart primary 450 500 
parted -s /dev/sdc unit MB mkpart primary 500 550 
parted -s /dev/sdc unit MB mkpart primary 550 600

如果在生产环境的Oracle数据库中,block_size=2K的表空间,单个数据文件最大8G,可以使用:

parted -s /dev/sdc unit GB mkpart primary 1 8 

2. 设置udev规则。如何在CentOS 6中设置udev,可以参看我之前的文章 - How to use udev for Oracle ASM in Oracle Linux 6

vi /etc/udev/rules.d/99-oracle.rules

添加如下行:

KERNEL=="sd?[1-9]", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/name", RESULT=="36000c293bd690056ce6834434765d3f4", NAME="oradisk0number", SYMLINK="mapper/name", OWNER="oracle",  GROUP="dba", MODE="0660"
KERNEL=="sd?1[0-9]", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/name", RESULT=="36000c293bd690056ce6834434765d3f4", NAME="oradisknumber", SYMLINK="mapper/name", OWNER="oracle",  GROUP="dba", MODE="0660"

重启udev服务:

start_udev

然后可以发现/dev/mapper下的链接都成功创建,并且指向规则中定义的块设备名称。

# ls -l /dev/mapper/
total 0
crw-rw----. 1 root root 10, 58 Dec 29 03:29 control
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk01 -> ../oradisk01
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk02 -> ../oradisk02
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk03 -> ../oradisk03
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk04 -> ../oradisk04
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk05 -> ../oradisk05
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk06 -> ../oradisk06
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk07 -> ../oradisk07
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk08 -> ../oradisk08
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk09 -> ../oradisk09
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk10 -> ../oradisk10
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk11 -> ../oradisk11

注意,此时/dev目录下,sdc1至sdc11设备都不再存在了,但是我们可以通过比较设备的major号和minor号来确认绑定是正确的。

# ls -l /dev/mapper/oradisk01
lrwxrwxrwx. 1 root root 12 Dec 29 03:29 /dev/mapper/oradisk01 -> ../oradisk01
# ls -l /dev/oradisk01
brw-rw----. 1 oracle dba 8, 33 Dec 29 03:29 /dev/oradisk01
# cat /proc/partitions | grep 33
   8       33      48128 sdc1

3. 直接使用/dev/mapper/oradisk*作为数据文件
由于在Oracle 10.2.0.2以后,Oracle已经可以用O_DIRECT标志直接打开块设备,而不是像以前版本那样,如果要跳过操作系统缓存直接读写磁盘设备,必须要用使用字符设备。在以前的版本中,因为要使用字符设备,所以才需要用raw命令去将某一个块设备映射为一个裸设备(字符设备)。而在Oracle 10.2.0.2以后则可以直接使用块设备(比如/dev/sdc1,比如udev映射以后的/dev/oradisk01,这些都是块设备),不过,虽然Oracle 10.2.0.2以后,Oracle可以直接读取块设备,但是在Oracle 11g以前,这个特性还不被OUI支持,如果要在OUI中使用,则需要使用符号链接(symbolic links),如我们用udev创建的/dev/mapper/oradisk*。
也就是在Oracle 10.2.0.2以后,Oracle 11g以前,需要使用/dev/mapper/oradisk*这样的符号链接作为数据文件。
在Oracle 11g以后,可以使用符号链接,也可以直接使用/dev/oradisk*作为数据文件。

如果你们认为有更优的最佳实践,欢迎讨论。当然我们也可以使用lvm或者Oracle ASM来处理数据文件的存储,这不在本文讨论范围内。

BTW: 一个有趣的bug?在测试中发现,如果在udev创建完符号链接之后,再使用parted来查看链接的分区情况,则会导致链接消失,而映射前的sdc1设备名重新出现。重启udev服务也无法将链接重新创建,但是用parted重新查看sdc1设备,则链接又重新出现,sdc1又重新消失。求解释。

--正常情况下有符号链接
[root@localhost ~]# ls -l /dev/mapper/oradisk01
lrwxrwxrwx. 1 root root 12 Dec 29 03:29 /dev/mapper/oradisk01 -> ../oradisk01
--映射前的sdc1设备是不存在的
[root@localhost ~]# ls -l /dev/sdc1
ls: cannot access /dev/sdc1: No such file or directory
--用parted检查链接,或者检查/dev/oradisk01块设备,效果是一样的
[root@localhost ~]# parted /dev/mapper/oradisk01
GNU Parted 2.1
Using /dev/mapper/oradisk01
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) q                                                                
--链接消失
[root@localhost ~]# ls -l /dev/mapper/oradisk01
ls: cannot access /dev/mapper/oradisk01: No such file or directory
--映射的块设备还在
[root@localhost ~]# ls -l /dev/oradisk01
brw-rw----. 1 oracle dba 8, 33 Dec 29 03:29 /dev/oradisk01
--原先的sdc1设备出现
[root@localhost ~]# ls -l /dev/sdc1
brw-rw----. 1 root disk 8, 33 Dec 29 04:29 /dev/sdc1
--重新用parted检查sdc1
[root@localhost ~]# parted /dev/sdc1
GNU Parted 2.1
Using /dev/sdc1
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) q                                                                
--符号链接重新出现
[root@localhost ~]# ls -l /dev/mapper/oradisk01
lrwxrwxrwx. 1 root root 12 Dec 29 04:38 /dev/mapper/oradisk01 -> ../oradisk01
--sdc1重新消失
[root@localhost ~]# ls -l /dev/sdc1
ls: cannot access /dev/sdc1: No such file or directory

VMware and scsi_id

VMware Fusion中测试Cent OS 6中的udev功能时,发现scsi_id命令无法返回设备的SCSI ID。

# fdisk -l /dev/sdb

Disk /dev/sdb: 1073 MB, 1073741824 bytes
255 heads, 63 sectors/track, 130 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/sdb doesn't contain a valid partition table
# /sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/sdb

这个问题在Oracle VirtualBox中并不会出现,当然并不是说VirtualBox就比VMware好,作为Mac中的原生app,VMware Fusion确实要比VirtualBox美观,但是在功能上而言,VirtualBox毫不逊色,而且VirtualBox是免费的,所以如果要在自己的台式机或者笔记本中测试虚拟机,仍然强烈推荐使用VirtualBox。

言归正传,如何修改VMware Fusion,让其可以提供正确的设备SCSI ID呢?参考文章是:
The Case of VMware and the missing SCSI ID

方法如下:
1. 在虚拟机关闭以后,进入虚拟机的目录

2. 用文本编辑器修改vmx文件

$ ls *vmx
[ VMplanet ] CentOS 6.0.vmx
$ vi "[ VMplanet ] CentOS 6.0.vmx"

3. 在vmx文件中任意位置(通常在最后)添加如下行:

disk.EnableUUID = "TRUE"

4. 重新启动虚拟机,此时可以正确获取SCSI ID

#/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/sdb
36000c29577b5db74013db535e0155e01

注意:在手工修改完vmx文件以后,如果再进行任何虚拟机的设置,比如添加磁盘,修改网卡类型或者其它的操作,disk.EnableUUID参数又会重置为FALSE,所以每次进行虚拟机设置以后,都需要手工再次修改该参数。当然重启虚拟机,或者虚拟机内Guest操作系统中的任何操作,都不会重置该参数。

How to Recover Datafile Which Deleted Accidentally in Linux

今天有客户的数据库意外被删除了整个目录中的数据文件,操作系统级别的删除,然而幸运的是这个数据库没有崩溃,仍然处于open状态的时候,客户就发现了问题,求助到我们,最终完整地恢复了所有数据文件。

在Linux下大致重新演示一下恢复的过程,恢复的步骤与数据库版本没有太大关系,与操作系统的不同会有所不同。

1. 在数据库open的时候,直接删除users表空间中的数据文件。

SQL> select name from v$datafile;

NAME
--------------------------------------------------------------------------------
/app/oracle/oradata/ORCL/datafile/o1_mf_system_555wqbnk_.dbf
/app/oracle/oradata/ORCL/datafile/o1_mf_undotbs1_555wqxgl_.dbf
/app/oracle/oradata/ORCL/datafile/o1_mf_sysaux_555wr5p6_.dbf
/app/oracle/oradata/ORCL/datafile/o1_mf_users_555wrj4o_.dbf
 
SQL> host rm /app/oracle/oradata/ORCL/datafile/o1_mf_users_555wrj4o_.dbf

2. 尝试在users表空间中创建表,开始报错。

SQL> create table t tablespace users as select * from dual;
create table t tablespace users as select * from dual
                                                 *
ERROR at line 1:
ORA-01116: error in opening database file 4
ORA-01110: data file 4:
'/app/oracle/oradata/ORCL/datafile/o1_mf_users_555wrj4o_.dbf'
ORA-27041: unable to open file
Linux Error: 2: No such file or directory
Additional information: 3

在告警日志中,同样也可以看到类似信息。

Mon Dec 19 21:48:17 CST 2011
Errors in file /app/oracle/admin/orcl/bdump/orcl_m000_3897.trc:
ORA-01116: error in opening database file 4
ORA-01110: data file 4: '/app/oracle/oradata/ORCL/datafile/o1_mf_users_555wrj4o_.dbf'
ORA-27041: unable to open file
Linux Error: 2: No such file or directory
Additional information: 3

3. 检查dbwr的进程PID

$ ps -ef|grep dbw0|grep -v grep
oracle    2879     1  0 21:38 ?        00:00:00 ora_dbw0_orcl

4. dbwr会打开所有数据文件的句柄。在proc目录中可以查到,目录名是进程PID,fd表示文件描述符。

$ cd /proc/2879/fd
$ ls -l
total 0
lr-x------ 1 oracle dba 64 Dec 19 21:50 0 -> /dev/null
lr-x------ 1 oracle dba 64 Dec 19 21:50 1 -> /dev/null
lr-x------ 1 oracle dba 64 Dec 19 21:50 10 -> /dev/zero
lr-x------ 1 oracle dba 64 Dec 19 21:50 11 -> /dev/zero
lr-x------ 1 oracle dba 64 Dec 19 21:50 12 -> /app/oracle/product/10.2.0/db_1/rdbms/mesg/oraus.msb
lrwx------ 1 oracle dba 64 Dec 19 21:50 13 -> /app/oracle/product/10.2.0/db_1/dbs/hc_orcl.dat
lrwx------ 1 oracle dba 64 Dec 19 21:50 14 -> /app/oracle/product/10.2.0/db_1/dbs/lkORCL
lrwx------ 1 oracle dba 64 Dec 19 21:50 15 -> /app/oracle/oradata/ORCL/controlfile/o1_mf_555wq3ng_.ctl
lrwx------ 1 oracle dba 64 Dec 19 21:50 16 -> /app/oracle/oradata/ORCL/datafile/o1_mf_system_555wqbnk_.dbf
lrwx------ 1 oracle dba 64 Dec 19 21:50 17 -> /app/oracle/oradata/ORCL/datafile/o1_mf_undotbs1_555wqxgl_.dbf
lrwx------ 1 oracle dba 64 Dec 19 21:50 18 -> /app/oracle/oradata/ORCL/datafile/o1_mf_sysaux_555wr5p6_.dbf
lrwx------ 1 oracle dba 64 Dec 19 21:50 19 -> /app/oracle/oradata/ORCL/datafile/o1_mf_users_555wrj4o_.dbf (deleted)
lr-x------ 1 oracle dba 64 Dec 19 21:50 2 -> /dev/null
lrwx------ 1 oracle dba 64 Dec 19 21:50 20 -> /app/oracle/oradata/ORCL/datafile/o1_mf_temp_555wrbnz_.tmp
lr-x------ 1 oracle dba 64 Dec 19 21:50 21 -> /app/oracle/product/10.2.0/db_1/rdbms/mesg/oraus.msb
lr-x------ 1 oracle dba 64 Dec 19 21:50 3 -> /dev/null
lr-x------ 1 oracle dba 64 Dec 19 21:50 4 -> /dev/null
l-wx------ 1 oracle dba 64 Dec 19 21:50 5 -> /app/oracle/admin/orcl/udump/orcl_ora_2871.trc
l-wx------ 1 oracle dba 64 Dec 19 21:50 6 -> /app/oracle/admin/orcl/bdump/alert_orcl.log
lrwx------ 1 oracle dba 64 Dec 19 21:50 7 -> /app/oracle/product/10.2.0/db_1/dbs/lkinstorcl (deleted)
l-wx------ 1 oracle dba 64 Dec 19 21:50 8 -> /app/oracle/admin/orcl/bdump/alert_orcl.log
lrwx------ 1 oracle dba 64 Dec 19 21:50 9 -> /app/oracle/product/10.2.0/db_1/dbs/hc_orcl.dat

注意其中“/app/oracle/oradata/ORCL/datafile/o1_mf_users_555wrj4o_.dbf (deleted)”字样,表示该文件已经被删除,如果是Solaris操作系统,ls命令不会有如此清晰的显示,为了在Solaris系统中确认哪个句柄对应哪个文件,则需要使用lsof程序。

5. 直接cp该句柄文件名回原位置。

cp 19 /app/oracle/oradata/ORCL/datafile/o1_mf_users_555wrj4o_.dbf

6. 进行数据文件recover

SQL> alter database datafile 4 offline;

Database altered.

SQL> recover datafile 4;
Media recovery complete.
SQL> alter database datafile 4 online;

Database altered.

完成数据文件恢复。

恢复的原理是,在Linux操作系统中,如果文件从操作系统级别被rm掉,之前打开该文件的进程仍然持有相应的文件句柄,所指向的文件仍然可以读写,并且该文件的文件描述符可以从/proc目录中获得。但是要注意的是,此时如果关闭数据库,则此句柄会消失,那么除了扫描磁盘进行文件恢复之外就没有其它方法了,因此在数据库出现问题的时候,如果不确认情况的复杂程度,千万不要随便关闭数据库。重启数据库往往是没有意义的,甚至是致命的。

当然,客户的操作系统是Solaris,并且客户删除的文件还包括current online redo log,因此还有其它更复杂的操作,不在这里描述。