一个55TB的Oracle RAC (ASM)恢复案例

前几天某客户的一个数据库出现故障,需要我们紧急救援支持。了解了一下环境,着实也吓了一跳,数据量55TB左右。首先我们来看看故障的信息:

从前面的日志可以看出,该数据库节点从25号22:57开始报错,开始可能是出现了部分session hung的情况,接着出现了写失败的操作。而其中写失败的是第35个磁盘。

当然,这里仅仅是一个warning,因此我们还不能判断是磁盘是否有问题。

后面我们跟客户了解,当时的现象应该是存储链路出现了异常,导致数据库IO出现异常。这也符合之前的现象描述。

那么我们进一步分析后面客户的操作,看看之前他们都进行了哪些相关的操作?

我们可以看到,客户进行了正常的alter database open,但是Oracle提示有部分文件需要recover。那么进行recover database操作呢,则提示有部分文件可能来自fuzzy backup.

这是什么意思呢? 这其实是说这几个文件的检查点比较旧,需要很早之前的日志来进行recover。

由于这是一个非归档的数据库,因此很可能有问题的这几个文件需要日志已经被覆盖。

通过比较scn,我们可以判断这几个文件需要的redo信息已经被覆盖了。这里我要提醒大家的是,不要仅仅只看alert log就轻易下判断。

仅仅看alert log我们可能认为只有几个文件问题。后续我想,如果是仅仅有几个文件有问题,那么我跳过这部分文件进行recover 不就行了吗? 因为这样可以实现数据的最大程度恢复。

于是我执行了下面的命令:

上面这个命令,其实是比较致命的,因为Oracle 会将这里skip的表空间里面的文件全部进行offline drop。

所以这里其实上述的做法是有些欠妥的。

我进一步根据文件的scn和v$log的scn 信息进行比较,发现其实有605个文件可能都需要进行recover;因为全库已经有2000个左右的数据文件。

这里我根据scn进行大致判断然后产生2个脚本进行文件级别的recover,大致获取脚本如下:

通过将其他能够进行正常recover的文件进行恢复之后,尝试打开数据库。居然能够正常open数据库。有些人可能已经到此结束了吧,其实并不然。

大家想一下?虽然数据库打开了,我们不能正常recover的605个数据文件中可能还有部分数据文件状态是recover,也就是还不是online的状态。

这种情况之下,业务是无法访问的。实际上我这里查了一下,大概有540个文件状态仍然是recover。因此我们现在还需要想办法怎么去讲这部分文件online。

处理方法其实并不难,比如通过bbed简单修改下数据文件头的checkpoint信息,就可以完成了。但是有540个文件,而且都是ASM环境。

这个修改的工作量可想而已。后面再产生一个脚本,将数据库启动到mount状态,然后将之前状态为recover的文件全部online。

然后进行recover database using backup controlfile操作。接着直接进行alter database open resetlogs。

遗憾的是没有能够直接打开数据库,报了一个如下的错误,该错误很常见,mos有问题也提到,可能跟temp有关系。

 

 

 

 

这里我这里直接将tempfile 进行drop,然后再重建控制文件,进行recover后,居然直接打开数据库了。

检查alert log,我发现还存在一个如下的错误:

很明显,上述错误是指smon进程在进行事务恢复时,发现有2个事务无法进行恢复。

看到上述的错误,或许有人会说可能是undo出现损坏,导致无法进行事务恢复。实际上这里并不是,我通过dbv检查发现undo文件都是完好的。

无论怎讲,这里要解决这个问题,相对简单,定位到是什么对象,重建就好。

清明节某客户的11gR2 rac恢复案例

这是昨天节假如接到的某客户的紧急救援数据恢复案例。大致的情况是由于掉电导致数据库无法open。经过初步排查,确认数据库版本为Oracle 11.2.0.3(linux RAC),数据量比较小,

大约200G左右。整个恢复过程开始看上去很顺利,仅30分钟就顺利打开了数据库,后续发现其中确实有少坑,这里跟大家简单分享一下这个清明节加班的恢复case。

首先我们来看下数据库无法open所报的错误是什么?

这个错误其实很常见,已经遇到很多次了,处理方式也不难;大致上有两种.
1、通过10046 trace定位到有问题的数据块,然后手工去屏蔽事务;

2、推进数据库SCN
这里我选择使用推进scn的方式来进行处理。

直接通过oradebug poke修改scn;第一次修改可能是增加的scn不够大;第一次报错一样;第二次报错改变了;变成我们更加熟悉的错误:

 

上述的这个错误处理方式其实也有2种,大致如下:
1、由于scn差距很小,因此直接适当推进scn即可。

2、bbed修改dba地址20971648 中的事务来绕过该错误。

很明显,这里我选择第1种方法更简单;这里我再次修改scn,稍微增加大一点即可;很顺利的打开了数据库。

看上去整个恢复过程很简单,也就不到半小时就打开了数据库。可是当我检查数据库文件状态时,整个数据库一共有23个数据文件,其中有11个数据文件状态为missing,

这也就是说都无法识别到数据库文件。实际上此时数据库alert log中也在报如下的错误,告诉我们这部分数据文件无法识别:

由于此时数据库已经打开了,因此为产生了一个重建控制文件的脚本,发现脚本内容如下:

实际上我问客户,他们的反馈是之前由于控制文件损坏,客户也重建了控制文件,进行了多次恢复,而且也进行了resetlogs操作。

从上面的信息来看,不难看出客户重建控制文件的时候漏掉了11个数据文件。由于这部分文件的信息在数据字典中存在,因此在open的时候Oracle 会自动进行offline drop。
或许有人要说,直接找到文件然后重建控制文件不就行了吗?确实如此,然而实际上这里却并没有这么简单。
我进入到asm磁盘组检查文件发现有几个文件名称很奇怪,例如user_02.dbf 实际上link到了system,类似这样的情况。
这种情况下极容易出错。争取的做法查询dba_data_files进行数据文件的挨个确认。
确认好asm磁盘组漏掉的4个文件之后,还有7个文件位于文件系统中。全部添加到脚本中进行创建时发现这些文件和之前到文件到resetlogs已经完全不同了。
其实创建控制文件会报错ora-01189。
因此这里还必须手工去修改这11个数据文件头的resetlogs信息;等我将resetlogs信息全部修改完毕后,可以顺利创建控制文件。
但是当我进行reconver时却发现需要之前等archivelog,进一步检查发现归档日志都全部被删掉了。
因此最后还必须的再次修改这部分数据文件的checkpoint信息,将其改成与其他正常的文件一致,最后可以顺利打开数据库,

且检查所有的数据库文件状态均为online状态,如下所示:

最后再将文件系统的文件迁移到asm磁盘组,然后添加redo信息,启动rac节点2.

某客户Oracle RAC(4 TB ASM) 数据库恢复案例

6月底我们接到某客户的紧急支持请求,其客户数据库在不久前由于机房停电,导致数据库重启后无法启动。

我们通过teamviewer远程初步分析了alert log以及kfed读取了几个disk 发现,数据库无法启动的根本原因在于ASM diskgroup无法mount。而ASM diskgroup 无法mount的根本原因在于,ASM元数据出现损坏,其中表现为ASM 启动时无法进行事务恢复。

这里我们先不去纠结为什么会坏。对于asm的元数据如果出现损坏,那么修复的难度可想而知。

这里我采取了非常简单的数据库恢复方案,计划用AMDU抽取数据库文件,然后将数据库open,最后再重建原数据库磁盘组,最后通过Oracle rman 的backup as copy 方式将数据库还原回去。

想象是比较美好的,经过与客户长达1天的沟通协调之后,发现客户根本协调不到存储资源,而数据库环境本地可以空间也就不足100G。我们知道,整个数据库的磁盘组是6TB,其中数据库文件大约在4T左右,显然这是比较麻烦的事情。

无奈之下,客户从京东买了一个6TB的移动硬盘,经过一番努力之后,挂上移动硬盘,通过AMDU抽取文件测试,发现速度大约为5m/s。这是一个500m的undo文件复制到移动硬盘的速度测试:

大家可以计算一下,大约需要10天左右。这样是这样进行下去,那么整个恢复过程估计需要15天了,这是无法接受的。

后面跟客户了解了一下,客户的应用服务器是windows环境,我通过在windows共享文件,NFS共享到soalris,测试amdu抽取文件的速度大约可以达到15m/s。虽然这也是非常之慢的,但是相比之前已经好很多了,客户也可以接受了。

这里不得不说一下windows和Soalris之间配置NFS共享,也是一个比较麻烦的事情。折腾了几个小时才搞定这个问题。这里我简单记录一下配置的步骤,如下:

后续的步骤相对就简单了,都是传统的数据库恢复套路。如下是AMDU抽取文件的步骤:

这里我们需要注意的是,amdu不仅可以抽取数据文件,还可以抽取spfile、controlfile、以及redo、archivelog等。

对于AMDU工具抽取文件的过程,就单纯的命令而言,这是比较简单的。其中的关键就是我们必须知道文件在ASM diskgroup中对应的asm file number号。注意,这里的file number,并非数据库(DB)中的file number。

Oracle ASM的元数据中,其中alias directory 里面记录了数据库文件和asm 之间的一个映射关系。也就是说我们只要能够通过kfed读取alias 的数据,也就能够知道数据文件的asm file number是多少。

当然,很多情况之下,如果你添加数据库文件是alter tablespace xxx add datafile ‘+DATA’  …这样的方式,那么直接查询控制文件即可获得asm file number。这里不多说。

最后我dbv check了一下数据库文件,发现就undo存在几个坏块,其他文件均ok。不过比较郁闷的是,进行正常recover database恢复时,提示需要recover的归档找不到。这是怎么一回事呢?

我们来看下数据库文件头的scn 情况。

我们可以发现,从文件头的scn来看,差距大概在3个小时左右。而recover 时也确实需要比较旧的archivelog。而这中间差距的几个小时的归档,我们通过kfed 读取asm diskgroup元数据发现并没有找到。

为什么会丢失呢?其实很简单,可能这3个小时的归档也就6个archivelog,很可能在存储cache中,并没有写入到磁盘上。那么当掉电之后,这几个archivelog 肯定也丢失了。

当归档不全的情况之下,我们amdu抽取的current redo logfile已经没有意义了。我们只能将该数据库强制open,然后重建数据库。这里我简单描述一下数据库的open过程,以及恢复过程中遇到的一些错误:

首先利用amdu 抽取的控制文件进行mount,发现报如下错误:

这个错误很常见,我们在数据库恢复过程中经常碰到该错误。假设你是第一次遇到这个错误,你该如何判断该错误是什么问题?跟什么东西有关系呢?从ORA-00600错误的关键字,kccpb可以看出,这跟控制文件有关系,其中还包含了check关键字。说明这是在数据库mount过程中,进行某些check检查,发现了某些数据异常。那么后面的2个数字:3811063,3770626是什么意思呢?

有人或许会说,这有没有可能是scn?这里不排除这种可能性,如果你稍微有一定经验,那么很容易排除这个可能性。为什么?

首先对于一个运行超过3年的Oracle数据库,scn不可能这么小。其次从Oracle 10g开始,会自动产生snap controlfile的备份,在ORACLE_HOME/dbs目录下,我们可以利用该备份进行mount,然后去检查数据库文件的scn情况。

那么这个错误到底是什么意思呢?这里我猜测肯定是某个sequence number的东西,Oracle在mount的过程中认为读取的数据应该是3811063,但是实际上读取的数据确实3770626,2者之间存在差异。也就是说,Oracle认为控制文件已经损坏。

实际上,Oracle metalink 针对该错误进行了详细描述,其实也提供了解决方案,供大家参考:ORA-00600: [kccpb_sanity_check_2] During Instance Startup (文档 ID 435436.1)

看过该文档的人应该都知道,解决该错误的方法就是利用备份进行恢复,要么就是重建控制文件。既然如此,那么我们就来重建控制文件吧:

重建完毕之后,进行一次不完全恢复,然后尝试直接open数据库,发现遇到如下错误:

这个错误也很常见。很多人都已经知道如何处理这种情况下,那就是推进SCN。那么这里如何推进scn呢?

由于该数据库是Oracle 10g,且没有安装最新的psu;因此我们可以直接使用oracle 10015 event来推进scn,命令如下:

alter session set events ‘10015 trace name adjust_scn level n’;

其中的n表示level,那么这个level应该是多少呢?应该是4*7=28,为了稳妥期间,我们一般设置比28稍微大一点,因此可以设置30.

经过10015 event的处理之后,再次open数据库,你会发现数据库已经open了,但是很快就会crash。因为会如下错误:

同一,该错误也太常见了。我们知道,对于ORA-00600 后面的错误编号,如果是在4000–6000的范围中,那么表示跟undo有关系。实际上我们之前dbv检查文件也确实发现undo有极少量的坏块存在。那么这里怎么处理这个问题呢?

既然undo存在文件,那么我们知道数据库在open的时候需要进行事务的rollback,而事务回滚则跟undo存在极大关系。那么这里我们可以通过几种方式来解决该问题:

1、通过undo_manangment=manual

2、._offline_rollback_segments

3、10513 event来禁止smon 进行事务恢复.

很明显,这里我选择第一种方式,更为简单,通过修改pfile即可很快解决该问题。通过参数修改很顺利打开了数据库,然后检查alert log发现会有如下类似的错误:

该错误,我相信不少同学都遇到过。从该错误的提示来看,就非常明确了,index key not found。也就是说这是index的问题。那么是什么对象呢? 也就是我们的obj# 5099。 对于object号大于56的,那么我们可以直接rebuild处理。

alert log中其实还有一些其他的错误,这里我们不在一一列举说明。前面已经提到过,由于cache丢失,那么数据库中的很多数据可能都不一致,如果通过修复alert log中的错误,然后提供业务运行,那么存在极大的风险。因此建议重建数据库比较好一些。

这里我们首先将undo进行重建处理,这样可以绕过很多错误,接着开始进行数据库重建工作。

补充:提供几篇文档供大家参考:

Step by step to resolve ORA-600 4194 4193 4197 on database crash (文档 ID 1428786.1)

 

数据库重启之后无法open的恢复案例

这是某网友的维护的一套数据库,据说是正常重启之后就无法启动数据库了。那么我们先来看看日志是什么样的:

我们可以看到,节点1在9:48:52秒被强行终止重启了实例。而且我们还可以看出该节点从9:42开始就出现ORA-27090 错误。而该错误通常跟操作系统有关系,通过后面的Linux-x86_64 Error: 4: Interrupted system call 错误也验证了这一点。

这里我们无论是看节点1还是节点2的alert log日志都会发现,由于smon进程在进程事务恢复时失败之后,导致数据库实例最终宕掉。宕掉之后就再也无法正常启动了。很明显这是强行关库之后带来的蝴蝶效应。
这里我们来看看其中节点2的这个ORA-00600 [16559]是什么含义?

从解释来看,这是Oracle 数据字典表tab$出现了不一致的情况。比较郁闷的是,客户的dataguard也坏掉了,也是一样的错误。
那么看来只能进行恢复了。这里首先要明白,节点1的ora-00600 [16703]本质上来讲跟ora-00600 [16559]是一回事。
从具体的错误来看,Oracle在open时,进行bootstrap初始化的过程就失败了,因此报错ORA-00704: bootstrap process failure.
处理思路也很简单,我们首先通过10046 trace跟踪open的过程,来看看Oracle 在bootstrap初始化的时候在进行什么操作时报错的?

从上面的错误不难看出就是在访问tab$ 的时候报错的,而且是访问的obj#=20的这个对象。那么这个对象是什么呢?

根据我们的查询以及对ORA-00600 [16703],[1403],[20] 这个错误的理解,那么我这里可以大致判断这个错误后的几个数字的含义:
16703: 错误代码,表示数据字典基表存在不一致1403: 表示数据没找到或者不匹配,即not data found.20: 表示访问的对象号,即object_id.
同时我们从前面的10046 trace跟踪来看,报错的SQL语句访问了3个block,然后报错,分别是file 1 block 50,51,26。
这我们分别dump 上面的3个block发现其中block 51,26 的dump 内容如下:

看到这里,我就想是否可以通过bbed先把这2个block 给修复了,看看是否能够起来。如下是简单的修复过程:
对于51号block 由于是Index 修改非常简单,这里不多说。26号block 是cluster table,这个相对复杂的多。首先提交事务、修改lock flag之后verify还是报错,如下:

这里继续修改聚簇对应的kdbr信息(这里以其中一个kdbr为例):

我们经过几处简单修改之后,再次verify校验已经不再报错了;不过再次open数据库时,发现报另外一个错误了:

从错误来看,bootstrap的初始化过程仍然有问题。通过10046 trace跟踪发现还是那几个block。
回想前面这个block的dump时,看到的几行操作是delete,如下:tl: 4 fb: -CHDFL– lb: 0x2  cc: 0 cki: 0
那么我们这里试做将这几个被删除的操作进行还原是否ok 呢? 也就是用bbed来恢复这7个delete操作。
由于是cluster table 的block,操作相对麻烦一些。不过我尝试修改之后,最后发现错误仍然一样。
其中[kdoirp-3]是什么含义呢? 我们来看下Oracle 文档的描述:

很明显,这表示insert row piece。 看来我们单纯的修改这2个block 并不能绕过这个问题。 实际上后面我dump分析发现又涉及到_next_object,又将问题复杂化了。
虽然我相信多折腾几次可以解决这个问题。但是操作确实麻烦,费劲。不过此时通过之前的备份restore出来的system文件已经ok了。这里我用bbed 将涉及到的几个block 进行替换,最后再修改resetlogs信息,重建控制文件之后,进行recover。
非常顺利的打开了数据库。最后检查alert log 还涉及到smon 回滚某个事务失败。那么如何完美处理呢?
首先dump undo header,然后获取该事务涉及的操作对象,然后使用如下参数屏蔽回滚段后,将undo表空间重建即可。
如下是dump undo header获取的信息:
针对这部分对象,由于破坏了事务的完整性,那么建议对表进行分析,其中Index进行重建。

比特币攻击案例的恢复

今天凌晨4:50节点公司400转过来的求助电话,来自广西某个医院的客户;电话中说数据库被攻击了,业务完全停止,言谈之中表现的时分地迫切和着急。

首先我们来看看数据库的日志是什么?

大家不难看出,很明显跟2016年11月份爆发的比特币攻击案例如出一辙。这又是sql rush Team干的好事。很显然,我们去年大力宣传的比特币攻击事件,仍然被很多企业客户所忽视,最终出现了今天的悲剧。言归正转,如何处理这个问题呢?

这里通过日志,直接查询最近有过ddl操作的对象,发现果然跟alert log完全一样。如下所说:

我们不难看出,上述6个对象,可能是问题的关键。那么我们就来看看上面6个对象的内容是什么。首先我们来看下trigger:

很明显,这是hacker创建的恶意trigger。遗憾的看上去名字是这样,具体查不到内容?既然如此,我们先来看看存储过程,发现3个存储过程都是加密的。通过解密之后,发现代码如下:

我们可以看出,SQL rush Team还是很熟悉Oracle的,对于dbms包的利用,比我们都熟悉呀!

通过看上述解密之后的代码,才恍然大悟,Hacker居然是在Trigger和存储过程名称后面加了9个空格;注意是9个空格,一个都不能少。

我们再仔细阅读前面2段代码,可以看出这是比较坑爹一个Heacker。通过轮寻会不断产生truncate table 的Job,而且做这些操作之前会通过表的分析时间来判断数据库的运行时间,如果超过1200天,则爆发这个勒索行为(因为长时间运行,说明数据库是有价值的)。

最后一个存储过程会限制程序等连接,导致客户业务无法访问数据库。

了解了上述3个存储过程之后,解决方法就不难了,大致如下:

1、alter system set job_queue_process=0 scope=both ;并重启db(为什么要重启呢?因为此时数据库肯定已经产生了大量的library cache lock,无法操作)。

2、drop上述trigger 和存储过程:

3、删除Hacker创建的大量Job

经过检查发现客户的业务用户portal_his下面被创建了14万个Job。由于内容实在是太多了,因此简单拼一个SQL来删除有问题的Job。

4、确认被truncate的表。

最后恢复之后,客户反映业务基本上正常,但是仍然有部分业务数据看不到,详查之下发现有部分表的数据看不到了?但是客户也说不上来,到底哪些表有问题?那么怎么判断呢?

其实很简单,通过dba_objects.last_ddl_Time来判断该业务用户下最近被ddl操作的表有哪些即可,最后发现有68个表。通过ODU恢复这部分被truncate的表数据即可。

 

请大家仔细检查你的环境,不要再出现类似的问题,为自己或公司造成损失!如果遇到此类问题,请联系我们,获取专业技术支持!

Oracle 9i遭遇ORA-00600 [OSDEP_INTERNAL]的恢复案例

前几天同事反馈说某客户的一套数据库出现异常,负载极高,服务器几乎无法操作,只能强行关闭服务器电源来重启数据库;悲剧的是重启服务器之后,数据库无法启动了。

首先我们来看看启动数据库报什么错误:

从上述的错误来看,mount之后,open数据库时报错ORA-00601,而且这是SMON进程抛出的错误;可见这是smon进程在进行事务恢复时抛出的错误,最后的结果就是smon强行终止了实例。这就是为什么同事反馈,只要执行alter database open命令,sqlplus 窗口就报错ORA-03113. 如下是对于trace文件的call stack信息:

我们继续看后面的几个ORA-错误,我们都知道,对于这种一连串的错误,需要从下往上看,即ORA-00601错误是关键,是起因,然后再导致了ORA-27303,ORA-27302 等等错误。

从错误的基本解释来看,基本上判断是存在锁冲突,数据库都没有open,怎么会有锁呢?所以我们不难看出,这应该是操作系统数据库实例的内存没有清理干净。

果然,我ipcs -a查看看到有几个之前启动过的实例还分配着内存呢,同时也还有一些ora-进程存在。通过ps -ef|grep ora|grep -v grep|awk ‘{print $2}’|xargs kill-9 杀掉进程之后,再ipcrm -m 清除即可。

接着尝试启动数据库,手工进行recover database发现又报其他的错误:

这个错误还是比较少见的。最后的这个ORA-00600 [kcoapl_blkchk] 我也是第一次遇到,不过结合前后日志来看,很明显这是数据库在通过redo进行数据块应用时出现了异常,而有异常的数据块则是file 1 block 164301;也就是我们的system 文件。

其次我们也可以看出,该数据块所涉及的对象是data object# 3,也就是我们常说的bootstrap 核心对象,但是这是一个Index。

如果我们再看的仔细一点,可以发现这个块的问题是出在了事务层,因为有ora-10561错误产生。

既然如此,那么我们首先来dbv 检查一下数据库的system文件,看看是否有物理损坏:

通过dbv的结果来看,system 文件本身是没有物理损坏的。如果不是物理损坏,那么结合前面的错误信息来看,我们可以判断这个文件的这个块应该是逻辑损坏。这里我们应该可以通过rman 进一步进行检查确认。

为了尽快启动数据库,这里我们先通过如下的方式来尝试进行恢复:

很顺利的打开了数据库,这也说明目前数据库的问题并不是很严重,只是有问题的数据块并不多,否则上述的命令是不会起到什么作用的。

这里我简单补充一点,对于allow  n corruption的操作,在Oracle 9i 和10g 版本中,仅仅支持1个corrupt block;而在11gR2版本开始,则可以支持多个,最多可达10个 corrupt block。

打开数据库之后,我检查了数据库alert log发现,有一些其他的错误,如下所示:

单纯的看到上述错误,我开始以为是不是因为我们前面执行了allow 1 corruption的恢复,所以导致sql执行报错。

针对该错误,我查询了一下Oracle metalink,其中的文档ORA-600 [25012] “Relative to Absolute File Number Conversion Error” (文档 ID 100073.1) 提到该错误则表示可能是存在物理损坏。其中[0] 表现表空间编号,[852]表示相对文件号。

但是根据实际的情况来看,这似乎不对,因为这个数据库目前仅有200多个数据文件,不太可能出现文件号大于800的情况。其次dbv 检查system文件确实是没有物理损坏。

这里我们姑且不管mos文档是不是对的,就只看这个错误来看,是调用的监控脚本运行出错,监控脚本的本意是通过查询数据库dba_segments试图来获取数据库的大小。

那么我们进一步看看dba_segments的访问是否会涉及到我们前面提到的data object# 3呢? 通过vi trace文件,搜索Plan_table关键字即可看到报错SQL语句的执行计划,我发现并没有涉及到data object# 3的对象。

由此可见,这个数据库除了我们前面提到的data object# 3,还有其他的对象可能也存在逻辑不一致的错误;因此建议进行全库级别的一致性检查,如有必要,建议重建一下数据库。

对于这个问题产生的根本原因,我一直在思考,到底是什么原因呢?最开始我怀疑可能有如下几种可能性原因:

1、强制重启主机,导致主机cache 丢失,最终导致Oracle redo或datafile 存在write lost;

2、数据库的system文件之前就存在不一致的情况

3、Oracle bug

由于客户这套Oracle 9208数据库使用的是裸设备,因此Oracle 对于文件的读写按理说是不会应该操作系统cache的,因此不存在第一种情况的说法。所以我认为要么是数据库之前可能就有一定问题要么就是命中了Oracle的某个bug(具体是什么bug,没有去深入排查)。

这里我也提醒一下,对于Oracle 9i这种老库,尤其是非归档的情况,不建议强制重启,可能出现一些异常。

 

DataBase can’t be open after shutdown immediate

五一放假期间,某客户的数据库出现故障,据说对方找了一些工程师折腾了一天,都无法将数据库open,其中参考了网络上的很多文章,也使用了一系列隐含参数,均无法将数据库打开。这里我简单的与大家分享一下这个case。

首先我介绍一下整个case的背景,客户在4月30号凌晨通过shutdown immediate停库维护后,启动数据库无法报错,此时发现数据库无法open,期间尝试了各种数据库手段,均失败告终。我们先来看看相关日志,如下是数据库停库的日志:

我们可以看出,这个数据库确实是以shutdown immediate的方式停止的。客户第一次尝试启动时,发现报错ORA-00600 [2663],如下:

这是一个非常常见的错误,这个错误通常是是更数据块有关系。我们知道,根据经验,一般来讲,如果current scn (这里是scn base)与dependent scn(scn base)非常接近(且scn wrap都一致或者为0)的情况下,说明scn的差异非常小,通过多次重启数据库的手段,基本上可以绕过这个错误。果然,通过看客户提供的alert log发现多次重启后,alert log的报错日志变了ORA-00600 [4194]错误,如下:

这是一个看似非常简单的错误,大致意思是说Oracle 在进行事务恢复时发现redo和undo的信息有所出入,因此抛出这个错误。这里我仍然贴出Oracle MOS的标准解释供大家参考:Basic Steps to be Followed While Solving ORA-00600 [4194]/[4193] Errors Without Using Unsupported parameter (文档 ID 281429.1)

上述文档中提到,这个错误其实就是指恢复时发现undo block对应的record 编号与redo block 对应的undo record 编号不一致。通常情况下来讲,都是由于回滚段损坏导致的问题。 这里我们先不去进行alert log的详细分析展开了,以自己的实际操作过程来进行展开分析说明。如下是我的简单恢复过程。

首先我尝试进行正常恢复,并打开数据库:

我们可以看到操作报错,并没有打开数据库。此时查看数据库alert 告警日志,发现正是前面提到的ORA-00600 [4194]错误:

这个ora-00600 错误与前面提到的完全一致。根据我们常规处理这个错误的套路,基本上就是使用undo_management=’manual’ 来尝试绕过,经过测试发现不好使。进一步查看对应的trace 文件,发现oracle提示说某个块存在异常:

上述的错误其实也很容易解释,简单的讲就是redo应用时出现了异常,而且oracle 明确提升file 1 block 131 这个undo block有问题. 上述的内容是redo block的dump;那么我们来看看对应的undo block 中的前镜像是什么:

我们可以看到完全不匹配,同时我们通过脚本将上述内容进行转换,可以发现是其实是回滚段名称:

其次结合我们前面解释ora-00600  [4194]错误来看,这里undo block 对应的record number是0x20,而redo block中记录的record number是0x2. 这确实是不匹配的。

那么怎么解决这个问题呢? 能不能通过屏蔽回滚段的方式来解决呢?我尝试在open之前设置10046 trace,来观察了一下得到了如下结果:

可以看到oracle在执行update undo$时报错,其中更新的是_SYSSMU1_3724004606$ 这个回滚段。而且我们也可以看到,wait# 中记录的正好是前面报错的file# 1 block 131. 那么通过_corrupted_rollback_segments=(_SYSSMU1_3724004606$)这种方式是否可以解决这个问题呢?很遗憾,这里我测试也不行。甚至通过bbed 修改undo$的kdbr记录,将_SYSSMU1 的状态修改为offline,也无法绕过这个ora-00600 4194错误。
简直堪称最顽固的ORA-00600 [4194]。我又检查了一下前面的trace文件,发现所针对这个回滚段头的dump记录,可以确认其中并没有什么活动事务。
然后再仔细看我们所遇到的这个ora-00600 [4194]错误,我感觉有点怪异。为什么说怪异呢?如果说根据Oracle mos的解释文档来看,这里是是没有[a],[b] 值的,因为均为0.最后我们想到通过修改system 回滚段头来绕过这个错误,如下是操作过程:

 

注意,这里我们仅仅需要修改ktuxcnfb和ktuxcfbp[1] 即可。其中将ktuxcnfb修改为0,ktuxcfbp[1]中的uba修改为0.
然后再尝试打开数据库,发现顺利打开了数据库,如下:

接着检查了数据库alert log,也没有发现任何的ora-错误。
看到最后,或许大家会觉得很奇怪,为什么会出现这样的故障呢 ? 这里我也跟大家一样困惑。为什么说困惑呢?
因为这库是通过shutdown immediate方式正常停止的。我们都知道,这种方式停库之后,整个Oracle数据库的
文件都是处于一致的状态,重新启动数据库实例后按理说是不需要再进行实例恢复的。
那么为什么这里又出现了这种情况呢?
针对这个问题,我认为有2种可能性:
1、shutdown immediate之后,数据库写入到操作系统cache,还未完全写入到disk上时,此时数据库主机被强行重启;
由于操作系统cache丢失,导致数据库出现了不一致的情况(本文环境是Linux文件系统)。
2、其他程序或软件破坏了Oracle数据库文件的一致性(实际上,经过了解该环境部署了Rose HA软件;而且
客户在操作时,据说并没有停止rose ha软件)。
由于客户操作的时间点是凌晨2点,几乎是0业务场景,因此我认为第一种可能性几乎为0;第2种可能性更大。

Oracle open遭遇ora-01555错误

前几天我们的一位准客户的其中一套较为重要的数据库出现了故障。我们这里先姑且不去分析原因,来将数据库打开提供业务恢复再说。首先我们来看下一线工程师现场发回的报道:

从上述的错误来看。数据库在open时,其中一个递归SQL语句执行失败,该递归SQL执行失败的原因是出现了ora-01555错误,即大家所熟知的快照过旧;同时日志中也明确提到了需要访问的回滚段编号,即第37号回滚段。

根据我们一般的处理思路,需要进行10046 trace跟踪,确认这里的递归SQL是不是访问了一些存在活动事务的Block

 

10046 跟踪来看,报错的SQL 语句访问了2block;分别是file 1 block 337file 157 block 164013. 很明显第一个数据块应该是数据字典的block,而157号文件的这个block应该是undo block,因为这里的obj#=0.

接着我们来看看file 1 block 337 blockdump情况: