上文,在这一节中我们来观察一下使用TAF发生故障转移时,Oracle让Select语句能够继续执行的一些现象。

测试环境跟上文一样,但是TNSNAME配置有些变化,增加了“RETRY”和“DELAY”,增加的选项是为了避免在failover时,如果正在执行SQL,客户端报ORA-03113错误:

XTY =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.114)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = XTY)
      (FAILOVER_MODE =
        (TYPE = SELECT)
        (METHOD = BASIC)
        (RETRIES = 180) (DELAY = 5)         
      )
    )
  )

首先,我们在TEST用户下建一个测试的表,同时将系统的sql_trace参数设置为TRUE:

SQL> create table test.t1 as select * from dba_objects;

Table created.

SQL> alter system set sql_trace=true scope=spfile;

System altered.

在客户端,使用sqlplus连接数据库,连接的用户名为TEST。连接后,执行下面的语句:

SQL> spool 1.txt
SQL> select rownum,object_id,owner,object_name from t1 where rownum< =5000 order by object_id;

在客户端显示输出的过程中,在另一个会话重启数据库:

SQL> startup force;
ORA-32004: obsolete and/or deprecated parameter(s) specified
ORACLE instance started.

Total System Global Area 167772160 bytes
Fixed Size 1266392 bytes
Variable Size 100666664 bytes
Database Buffers 62914560 bytes
Redo Buffers 2924544 bytes
Database mounted.
Database opened.

正在查询T1表的会话,在数据库重启时,会短暂地停止,在我的测试中,停止时显示的输出为:

   1140       1186 SYS                            V_$WAITSTAT

在数据库重启完成后,sqlplus继续输出数据,直到完成所有输出:

1094       1140 SYS                            V_$LOGHIST 
1095       1141 PUBLIC                         V$LOGHIST  
1096       1142 SYS                            V_$SQLAREA 
......(输出很多,略过).....

我们在生成的sql trace文件中,可以看到下面的内容:

PARSING IN CURSOR #3 len=87 dep=0 uid=55 oct=3 lid=55 tim=1208634047724259 hv=533322034 ad='2999e344'
select rownum,object_id,owner,object_name from t1 where rownum< =5000 order by object_id
END OF STMT
PARSE #3:c=40994,e=476949,p=301,cr=172,cu=0,mis=1,r=0,dep=0,og=1,tim=1208634047724244
EXEC #3:c=0,e=131,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1208634047724505
FETCH #3:c=12998,e=12276,p=29,cr=64,cu=0,mis=0,r=1,dep=0,og=1,tim=1208634047736908
FETCH #3:c=0,e=50,p=0,cr=0,cu=0,mis=0,r=2,dep=0,og=1,tim=1208634047745324
FETCH #3:c=0,e=36,p=0,cr=0,cu=0,mis=0,r=2,dep=0,og=1,tim=1208634047745861

可以看到,发生会话failover重新连接之后,又重新执行了我们测试的那个SQL。但是输出的结果表明,客户端自动跳过了前面已经得到的数据。

我们继续做下一个测试。这一次我们将SQL修改一下:

Read the rest of this entry

一套运行在AIX 5.3,HACMP 5.4上的双节点RAC数据库,CRS和数据库的版本均为10.2.0.3;CRSD.BIN自动重启,并产生很多的CORE DUMP。
进入$ORA_CRS_HOME/log/<nodename>/crsd目录下,查看crsd日志文件,可以看到CRSD在重启时的日志如下:

2009-03-13 13:59:49.692: [ OCRRAW][11400]proprdc: backend_ctx->prop_sctx=[0x1017ed10]
2009-03-13 13:59:49.692: [ OCRRAW][11400]proprdc: backend_ctx->prop_sltsmx=[0x0]
2009-03-13 13:59:49.692: [ OCRRAW][11400]proprdc: backend_ctx->prop_sclsctx=[0x10365848]
2009-03-13 13:59:49.692: [ OCRRAW][11400]proprdc: backend_ctx->prop_ctx_ocrctx=[0x10362940]
2009-03-13 13:59:49.692: [ OCRSRV][11400]th_snap:8:failed to take backup prop_retval=26
2009-03-13 13:59:51.480: [ CRSOCR][11240]32OCR api procr_open_key failed for key CRS.CUR.ora!wydb3!ons. OCR error code = 3 OCR error msg:
2009-03-13 13:59:51.480: [ CRSOCR][11240][PANIC]32Failed to open key: CRS.CUR.ora!wydb3!ons(File: caaocr.cpp, line: 319)

2009-03-13 14:00:06.282: [ default][1][ENTER]32
Oracle Database 10g CRS Release 10.2.0.3.0 Production Copyright 1996, 2004, Oracle. All rights reserved
2009-03-13 14:00:06.282: [ default][1]32CRS Daemon Starting
2009-03-13 14:00:06.282: [ CRSMAIN][1]32Checking the OCR device
2009-03-13 14:00:06.285: [ CRSMAIN][1]32Connecting to the CSS Daemon
2009-03-13 14:00:06.705: [ CRSD][1]32Daemon Version: 10.2.0.3.0 Active Version: 10.2.0.3.0
2009-03-13 14:00:06.705: [ CRSD][1]32Active Version and Software Version are same
2009-03-13 14:00:06.705: [ CRSMAIN][1]32Initializing OCR
2009-03-13 14:00:06.713: [ OCRRAW][1]proprioo: for disk 0 (/dev/rwbsdb_ocr1_128m), id match (1), my id set (550012785,1028247821) total id sets (1), 1st set (550012785,1028247821), 2nd set (0,0) my votes (2), total votes (2)
2009-03-13 14:00:06.809: [ CRSD][1]32ENV Logging level for Module: allcomp 0

列出目录中的所有文件可以看到,最近几天都有core dump文件。仔细查看可以发现,每个core dump文件的间隔周期为固定的8.5小时。这是一个周期性的现象。

仔细查看上面的日志,”红色字体“的部分,引起了我的注意。这个错误,表明是在做某个东西的备份的时候报了错。应该是在备份OCR。core dump产生的周期和crsd自动重启的周期,都是固定的,这跟CRS会自动周期性地备份OCR比较吻合。

在METALINK上一番搜索,找到了BUG 5893629与这个故障现象比较符合。METALINK对这个BUG的描述称,CRS在备份OCR时,会在$ORA_CRS_HOME/cdata/<cluster_name>目录下生成一个temp.ocr,如果这个文件之前已经存在,会试图删除这个文件,而如果这个文件由于不是root用户所有,则就会导致crsd crash。这个BUG要在10.2.0.4才会修复。

根据对这个BUG的描述,进入到$ORA_CRS_HOME/cdata目录,这个目录下面有两个目录,一个是“crs”,另一个是"localhost“,一般来说,crs就是CRS集群的名称。进入这个目录,没有发现任何文件,看权限,root用户也可以建立文件。

问题在哪里呢?换一个角度思考,既然BUG描述中称不能删除旧的temp.ocr文件会导致crsd crash,那要是没有$ORA_CRS_HOME/cdata/<cluster_name>这个目录会怎么样,一样不能建立temp.ocr这个文件,那这种情况也会不会crash?这里$ORA_CRS_HOME/cdata目录下只有crs和localhost目录,如果按这种推理,如果cluster_name不是通常的”crs“呢?

不过当时有其他事情,离开了现场,不能得到CRS集群名字。不过幸运的是,我在日志文件中,在上面贴出的那段信息的前面,经过了一大段一大段的无用的信息之后,找到了下面的日志:

2009-03-13 13:59:49.391: [ OCRRAW][11400]rbkp:1: could not create the temp backup file [/oracle/crs/cdata/wydb_crs/temp.ocr]
2009-03-13 13:59:49.391: [ OCRRAW][11400]proprseterror: Error in accessing physical storage [26] Marking context invalid.

这里的日志就更明显了,就是不能创建”/oracle/crs/cdata/wydb_crs/temp.oc“这个文件。而前面的推断却不幸言中,CRS集群名字真的不是默认的"crs”,/oracle/crs/cdata这个目录下也的确没有wydb_crs这个目录。

让数据库维护人员在/oracle/crs/cdata目录中新建一个目录wydb_crs,经过一段时间的观察,故障不再出现,问题解决。

从这个故障中,我们得到一个教训,CRS有时真的很傻,为什么在备份时像这种不能创建文件的错误,不是写个日志忽略过去而是直接将进程crash了,并且还产生了core dump?为什么在安装CRS时,安装软件不自动建好这个目录,而只是按默认的"crs"名字建立目录?看来安装ORACLE软件的时候,CRS集群名字取默认值就行了。严重怀疑那个BUG是不是真的会解决这个问题(根据METALINK的描述,在备份时会随机生成一个文件名,而不再是固定的temp.ocr,但如果像这个案例中的故障,仍然会得不到解决。)

意外Truncate表的事情时有发生,ODU提供了方便的恢复Truncate表的功能。被Truncate的表,只要原来的空间没有被重用(即数据被覆盖),则数据都是可以恢复的。

如果发现一个表被意外地Truncate,而需要马上恢复。首先要做的就是关闭数据库,或者OFFLINE那个表所在的表空间,或者关闭所有应用。目的只有一个,确保空间不会被重用,数据不会被覆盖。

下面举例说明如何用ODU恢复被Truncate掉的表。

1. 建立两个测试的表T1和T2,这两个表的数据完全一样。建两个数据完全一样的表的目的在于方便在恢复后对比数据。

SQL> connect test/test
已连接。

SQL> create table t1 as select * from dba_objects;

表已创建。

SQL> create table t2 as select * from t1;

表已创建。

SQL> truncate table t1;

表已截掉。

2. 我们OFFLINE掉T1表的表空间(实际上在实际的系统中,如果有比较多的活动,则表空间不容易被OFFLINE下来)。然后做一个Checkpoint,让ODU能够读到最新的数据字典数据。

SQL> select tablespace_name from user_tables where table_name='T1';

TABLESPACE_NAME
------------------------------
TEST

SQL> alter tablespace test offline;

表空间已更改。
SQL> alter system checkpoint;

系统已更改。

3. 运行ODU,并unload数据字典。

ODU> unload dict
get_bootstrap_dba: compat header size:12
CLUSTER C_USER# file_no: 1 block_no: 177
TABLE OBJ$ file_no: 1 block_no: 241
CLUSTER C_OBJ# file_no: 1 block_no: 49
CLUSTER C_OBJ# file_no: 1 block_no: 49
found IND$'s obj# 19
found IND$'s dataobj#:2,ts#:0,file#:1,block#:49,tab#:3
found TABPART$'s obj# 230
found TABPART$'s dataobj#:230,ts#:0,file#:1,block#:3313,tab#:0
found INDPART$'s obj# 234
found INDPART$'s dataobj#:234,ts#:0,file#:1,block#:3377,tab#:0
found TABSUBPART$'s obj# 240
found TABSUBPART$'s dataobj#:240,ts#:0,file#:1,block#:3473,tab#:0
found INDSUBPART$'s obj# 245
found INDSUBPART$'s dataobj#:245,ts#:0,file#:1,block#:3553,tab#:0
found IND$'s obj# 19
found IND$'s dataobj#:2,ts#:0,file#:1,block#:49,tab#:3
found LOB$'s obj# 156
found LOB$'s dataobj#:2,ts#:0,file#:1,block#:49,tab#:6
found LOBFRAG$'s obj# 258
found LOBFRAG$'s dataobj#:258,ts#:0,file#:1,block#:3761,tab#:0

Read the rest of this entry

,

TAF,透明应用故障转移(Transparent Application Failover),是Oracle数据库提供的一项高可用特性,普遍应用于RAC环境中,当然也可以用于Data Guard和传统的HA实现的主从热备的环境中。

TAF中的Transparent和Failover,点出了这个高可用特性的两大特点:

  • TAF是用于故障转移的,也就是切换。当Oracle连接的会话由于数据库发生故障不可用时,会话能够自动切换到RAC中的其他可用的节点上,或者切换到Standby上面,或者切换到HA方式中的另一个可用的节点上面。
  • TAF的故障转移,对应用来说是透明的,应用系统不需要进行特别的处理就能够自动进行故障转移。

但是,TAF是完美的吗?是不是使用了TAF,应用就能真的无缝地进行切换呢?对应用和数据库有没有其他什么要求?要回答这些问题,我们需要全面地了解、掌握TAF。我始终认为,要用好一个东西,首先得掌握这个东西背后的工作原理与机制。

首先来看看Failover。Failover有两种,一种是连接时Failover,另一种则是运行时Failover。前者的作用在于,应用(客户端)在连接数据库时,如果由于网络、实例故障等原因,连接不上时,能够连接数据库中的其他实例。后者的作用在于,对于一个已经在工作的会话(也就是连接已经建立),如果这个会话的实例异常中止等,应用(客户端)能够连接到数据库的其他实例(或备用库)。

首先,TAF是ORACLE客户端提供的一项特性。使用TAF,对客户端的环境有一定的要求。比如JAVA的JDBC驱动、Oracle客户端的版本等(8i开始支持TAF)。这个问题将在本系统文章的后面部分详细描述。

下面看一个有趣的例子:

Read the rest of this entry

接上文《ODU命令详解 PartII》,本文继续介绍ODU的命令

5.scan 命令

scan命令用于扫描数据文件中的segment以及extent。主要作用在于没有SYSTEM表空间时的数据恢复,以及TRUNCATE表和DROP表之后的数据恢复。命令格式如下:

scan extent [tablespace <ts#> [datafile <rfile#>] ] [object <data_object_id>]

扫描时可以指定表空间(只能指定表空间号),表空间中的1个文件;也可以扫描指定的data_object_id。扫描完成后,将在ODU的运行目录下生成ext.odu文件以及segment.txt文件,后者包含了扫描所找到的段头。

下面是一个示例:

ODU> scan extent tablespace 11

scanning extent...
scanning extent finished.

在恢复没有SYSTEM表空间和DROP,TRUNCATE表之前,需要运行scan命令。

6.dump 命令

dump命令模仿oracle的"alter system dump datafile"命令,解析并显示oracle的块格式。目前支持的块包括文件头(只有部分信息)、数据段头、表和索引数据块,其他的块只显示块头。这已经足够大部分情况的使用。ODU的升级版将解析并显示UNDO的段头和数据块。

dump命令用于帮助分析块格式,在ORACLE不能启动时(比如在关键的数据字典对象上有物理或逻辑坏块),用于分析块。dump命令的格式如下:

dump datafile <file#> block <block#>

这个命令格式与oracle的"alter system dump datafile“类似,这里的文件号是绝对文件号。
下面是几个示例输出:

Read the rest of this entry

,