本文介绍了CQ公司用户FLZYY一次意外断电导致数据库崩溃,技术人员经过多方尝试无法对数据库进行恢复,当决定采用备份恢复时,在检查用户备份环境时发现竟然已经失效很久,在万般无赖的情况下求助于总公司,经过多方尝试,最终幸运的将数据库恢复,避免用户遭受巨大的损失,希望用户和渠道以此为戒,认真做好数据安全防范,避免类似事故再次发生。
关键字:宕机、数据恢复
这天阳光明媚,我正在公司埋头写文档中并为文档中的措辞作深思状时,远远的看到CQ公司的HHJ和KJ朝我这边走来,看到他俩一脸囧样的表情就晓得又是那家用户数据库出了问题,一问果不其然CQ渠道的一家重点用户FLZYY因为意外断电导致数据库崩溃,已经尝试了些修复方式但是无法恢复数据,更为郁闷的是该用户的备份策略六月份就已经失效,意味着如果不能恢复用户将丢失至少3个月的数据,后果不堪设想。还有什么说的呢?立即放下手上的工作,马上远程连接到用户处,看了下现场结果发现由于已经做了很多处理错误现象已经离原始状态有很大的差距,这明显不利用问题的判断,还好渠道在处理前做了问题环境备份,先要求恢复原始状态再说,在恢复问题环境的过程中,随便聊了聊用户备份策略失效的原因应该是用户自己责任心不强,没有定期检查备份策略,因为该用户年前已经签署了数据安全协议,签署的时候对备份有效性进行了检查并告知了用户检查方式,还对其检查职责作了明确的要求,不过可惜还是没有引起用户的足够重视。不过因这样即使这次真的数据丢失,用户也不会找些类似没有告知检查备份的理由把责任归咎于公司,看来数据安全协议的签署还是很有必要,特别是当面对这种情况的时候。
言归正传,现在不是追究谁的责任的时候,先想尽办法处理问题才是,转眼间问题环境已经恢复,接下来就开始对宕机原因进行分析。
依然是处理意外宕机的三部曲:启动、看错误提示和查看日志,首先当然是手工启动数据库了,如下:
SQL> startup
ORACLE 例程已经启动。
Total System Global Area 612368384 bytes
Fixed Size 4385062 bytes
Variable Size 706032359 bytes
Database Buffers 1412044042 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
ORA-01113:文件 1需要介质恢复
ORA-01110: 数据文件 1: '/u01/oracle/oradata/orcl/system01.dbf'
SQL>recover database;
ERROR:
ORA-03113: 通信通道的文件结束
从上面的操作可以看到,在数据库正常启动的情况下,提示需要介质恢复,随后按照提示做介质恢复数据库就会异常终止,至于什么原因导致异常终止,我们就需要查看数据库日志以获取更多详细的信息,在日志中,我们可以看到错误信息如下:
WARNING! Recovering data file 38 from a fuzzy backup. It might be an online
backup taken without entering the begin backup command.
parallel recovery started with 16 processes
Wed Aug 29 11:02:20 2012
Recovery of Online Redo Log: Thread 1 Group 2 Seq 945 Reading mem 0
Mem# 0 errs 0: /u01/oracle/oradata/orcl/redo02.log
Wed Aug 29 11:02:21 2012
Recovery of Online Redo Log: Thread 1 Group 3 Seq 946 Reading mem 0
Mem# 0 errs 0: /u01/oracle/oradata/orcl/redo03.log
Wed Aug 29 11:02:22 2012
Errors in file /u01/oracle/admin/orcl/bdump/orcl_p003_7905.trc:
ORA-00600: internal error code, arguments: [kddummy_blkchk], [1], [69792], [6117], [], [], [], []
Wed Aug 29 11:02:22 2012
Errors in file /u01/oracle/admin/orcl/bdump/orcl_p003_7905.trc:
ORA-10562: Error occurred while applying redo to data block (file# 1, block# 69792)
ORA-10564: tablespace SYSTEM
ORA-01110: data file 1: '/u01/oracle/oradata/orcl/system01.dbf'
ORA-10561: block type 'TRANSACTION MANAGED DATA BLOCK', data object# 2
ORA-00607: Internal error occurred while making a change to a data block
ORA-00600: internal error code, arguments: [kddummy_blkchk], [1], [69792], [6117], [], [], [], []
通过日志比较清楚的看到无法介质恢复的原因,可怕的00600错误,因为这种错误属于Oracle公司核心内部错误,官方建议一般就一句话:申请Oracle官方专业技术支持或通过备份进行恢复,目前看来备份恢复是没希望了,申请Oracle公司专业技术支持也不太现实,只能硬着头皮上了。
上归上但是也不能乱上,首先还是要明确这个错误产生的原因,从上下错误关联来看,这个错误应该是在应用在线redo日志的时候出现,这里我们就需要了解下Oracle意外终止后的启动过程,如下图:
在数据库运行的过程中,会因为断电或者其他的原因而发生故障。此时由于数据高速缓存中的脏缓存块还没有来得及写入到数据文件中,从而可能导致数据的丢失,在数据库启动的时候,系统监视进程SMON会在下一次启动例程的时候,自动读取重做日志文件并对数据库进行恢复。也就是说,进行将已提交的事物写入数据文件(已经写入到日志文件中而没有写入到数据文件中的数据)、回退未提交的事务操作,显然目前问题出在了SMON读取重做日志这一步,应该是无法读取在线redo文件,导致无法完成恢复操作,因此本次无法启动的原因我初步断定是出在redo由于突然断电造成损坏,重启db后,造成系统表空间不一致,实例无法启动。
在线日志的问题我们一般处理方式是通过设置隐含参数_allow_resetlogs_corruption强制启动数据库,当然前提条件是数据文件的SCN号要一致,这里我已经检查了SCN号,确实是一致的,因此就直接设置了该参数,准备强制启动数据库,结果如下:
SQL> startup
ORACLE 例程已经启动。
Total System Global Area 612368384 bytes
Fixed Size 4385062 bytes
Variable Size 706032359 bytes
Database Buffers 1412044042 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
ERROR:
ORA-00600: internal error code, arguments: [4000], [10], [], [], [], [], [], []
看来事情果然不是想象中的这么简单,不然也不会流转到我这里,可以看到虽然加了隐含参数,但是数据库还是不能启动,而且出现了另外个00600错误,打开日志文件,查找更多的错误信息,重点内容如下:
Successful open of redo thread 1
Wed Aug 29 12:52:56 2012
MTTR advisory is disabled because FAST_START_MTTR_TARGET is not set
Wed Aug 29 12:52:56 2012
SMON: enabling cache recovery
Wed Aug 29 12:52:57 2012
Errors in file /u01/oracle/admin/orcl/udump/orcl_ora_8769.trc:
ORA-00600: internal error code, arguments: [4000], [10], [], [], [], [], [], []
Wed Aug 29 12:52:58 2012
Errors in file /u01/oracle/admin/orcl/udump/orcl_ora_8769.trc:
ORA-00704: bootstrap process failure
ORA-00704: bootstrap process failure
ORA-00600: internal error code, arguments: [4000], [10], [], [], [], [], [], []
Wed Aug 29 12:52:58 2012
Error 704 happened during db open, shutting down database
USER: terminating instance due to error 704
Instance terminated by USER, pid = 8769
ORA-1092 signalled during: alter database open resetlogs...
从这段日志描述看到,虽然还是无法启动,但是错误提示已经有所不同,这次是0ra-00600 [4000]错误,这也是个经典600错误,需要结合具体是trace日志分析,本案例的日志为(/u01/oracle/admin/orcl/udump/orcl_ora_8769.trc),过程我们在这里就不作具体阐述只要晓得其是由于非法的SCN号导致了,我们只需要将数据库的SCN整体向前推进消除掉这个SCN差异,数据库就会通过延迟提交清除这个事务信息,错误即可解除,而Oracle提供了个隐含参数_minimum_giga_scn可以推进scn号,使其跳过非法scn号,但是我们必须知道到底要推进多少,这里我们就需要在告警日志中找到最后一次完成的块清除SCN(CSC),在日志中找到如下内容:
Block header dump: 0x0040007a
Object id on Block? Y
seg/obj: 0x12 csc: 0x00.1484e1e itc: 1 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000a.027.0000d9e8 0x00800e0a.27a9.0a --U- 1 fsc 0x0000.01484e1f
其中红色字体部分就是CSC的值,它是16进制,我们需要把它换算为10进制,并且除以 1024*1024*1024,具体操作为:
0x00.1484e1e=>0x001484e1e=>88128741376=>88128741376/1024/1024/1024=82.06=83
_minimum_giga_scn设置的值就为我们刚才演算的83,即_minimum_giga_scn=83,然后再次做了以上操作,尝试启动数据,情况如下:
SQL> startup mount
ORACLE 例程已经启动。
Total System Global Area 612368384 bytes
Fixed Size 4385062 bytes
Variable Size 706032359 bytes
Database Buffers 1412044042 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
SQL> recover database until cancel;
介质恢复成功
SQL>alter database open resetlog;
ERROR:
ORA-00600: internal error code, arguments: [4193], [2389], [10157], [], [], [], [], []
看来真是一个错接另一个啊,有完没完啊,没办法,只能又接着处理,不过当看到Ora-00600 [4193]这个错误我心理有了点底气,因为这是一个常见的600错误,以前处理过类似的错误,原因是由于undo文件不一致导致,这个问题处理相对比较简单,流程都是一样的,如下:
1) 设置隐含参数_corrupted_rollback_segments,屏蔽出错的回退段,设置如下;
_corrupted_rollback_segments ='_syssmu1$','_syssmu2$','_syssmu3$','_syssmu4$','_syssmu5$','_syssmu6$','_syssmu7$','_syssmu8$','_syssmu9$','_syssmu10$','_syssmu11$','_syssmu12$'
2) 修改 undo_management 这个参数
把参数文件中的 undo_management 改为 MANUAL
做了以上设置后,再次尝试启动数据库,经过一阵稍长的等待,美妙的提示出现了,如下:
SQL> startup
ORACLE 例程已经启动。
Total System Global Area 612368384 bytes
Fixed Size 4385062 bytes
Variable Size 706032359 bytes
Database Buffers 1412044042 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
数据库已经打开。
至此用户在停机7个小时候,终于把数据库实例重新启动,但是以为现在就万事大吉还为时过早,由于启动过程中使用了隐含参数,数据库本身是存在隐患的,难免会再次出现意外的故障,为了保证数据库的完整性,最好的方式就是把数据导出然后重建数据库实例,这部分操作我们就不再描述,总之在经过这一系列处理后,用户的数据终于得以恢复,真是不幸中的万幸。
通过本文的介绍,再次强调了数据安全和备份的重要性,虽然看起恢复过程比较简单,几个隐含参数就解决了,但是其中的分析和结果过程的滋味只有真正身临其中才能体会,当然在解决问题的过程中,确实也得到了几点体会:
1. 理解数据库启动过程,有利用分析启动错误出现的原因。
2. 多利用日志信息,那里面包含了更多的错误信息,便于分析问题的真正原因。
3. 有些600错误并不可怕,多利用网络和Oracle官方资源
4. 合理利用隐含参数,有时能取得意想不到的效果
最后希望本文能对其他同事在处理类似问题提供有益的思路,在工作中共勉。