以下是和并行恢复相关的一个具体案例。
故障起因是由于工程师对一个10G大表进行imp操作,imp语句如下
imp username/passwd file=G:\mobile.dmp log=G:\ mobile_old.log ignore=y buffer=8192000 feedback=10000
这里导出文件mobile.dmp的大小有6G,由于失误未使用commit=y参数,这导致导入数据没有分批量提交,当导入执行了几个小时后,由于对业务系统产生了极大的压力和影响,imp操作被强行中断,这个中断导致了这个大事务的回滚,噩梦从此开始。
随后对该对象的Trucate/Drop操作都随之挂起,系统开始回滚,检查回滚段可以找到这个大事务的回滚段:
SQL> select * from v$rollstat where xacts >0; USN LATCH EXTENTS RSSIZE WRITES XACTS GETS WAITS OPTSIZE HWMSIZE SHRINKS WRAPS EXTENDS AVESHRINK AVEACTIVE STATUS CUREXT CURBLK --- ----- ------- ---------- ------ ----- ------ ----- ------- ---------- -------- ----- ------- ---------- ---------- ------ ------ ------ 3 3 3571 2066300928 0 1 445173 41 2066300928 0 0 0 0 0 ONLINE 3569 159
注意到这个回滚段已经扩展到2,066,300,928 Bytes大小,也就是约2G大小,这个回滚段所涵盖的数据都需要回滚。初始的系统参数FAST_START_PARALLEL_ROLLBACK设置为LOW:
SQL> show parameter parallel_rollback NAME TYPE VALUE ------------------------------------ ----------- ----------------------------- fast_start_parallel_rollback string LOW SQL> show parameter cpu_count NAME TYPE VALUE ------------------------------------ ----------- ----------------------------- cpu_count integer 4
系统启动了8个并行进程进行并行回滚,但是回滚执行了10个多小时仍然未完成(v$session的等待事件显示并行恢复产生了竞争,在此类情况下,通常串行恢复是更适宜的):
SQL> select sid,program,event from v$session where PROGRAM like '%P%'; SID PROGRAM EVENT ---------- -------------------- ---------------------------------------- 533 ORACLE.EXE (P003) db file sequential read 534 ORACLE.EXE (P006) db file sequential read 535 ORACLE.EXE (P007) wait for a undo record 536 ORACLE.EXE (P004) db file sequential read 537 ORACLE.EXE (P005) db file sequential read 538 ORACLE.EXE (P002) wait for a undo record 540 ORACLE.EXE (P000) wait for a undo record 541 ORACLE.EXE (P001) db file sequential read 550 ORACLE.EXE (CKPT) rdbms ipc message 554 ORACLE.EXE (PSP0) rdbms ipc message 555 ORACLE.EXE (PMON) pmon timer
随后尝试修改了FAST_START_PARALLEL_ROLLBACK设置为HIGH,然后数据库启动了16个并行进程进行恢复:
Wed Jan 24 09:21:06 2007 SMON: parallel recovery restart with degree=16 (!=8) Wed Jan 24 09:21:18 2007 SMON: Restarting fast_start parallel rollback Wed Jan 24 09:21:19 2007 ALTER SYSTEM SET fast_start_parallel_rollback='HIGH' SCOPE=BOTH; 这个恢复最终持续了一个小时左右,以SMON出错而结束,最后SMON终止了16个并行进程,启动了一个恢复进程进行恢复,smon的TRACE文件报了如下信息: *** 2007-01-24 09:21:06.334 *** SERVICE NAME:(SYS$BACKGROUND) 2007-01-24 09:21:06.318 *** SESSION ID:(549.1) 2007-01-24 09:21:06.318 *** 2007-01-24 09:21:06.334 SMON: parallel recovery restart with degree=16 (!=8) Parallel Transaction recovery caught exception 30312 *** 2007-01-24 09:21:18.553 Parallel Transaction recovery caught error 30312 *** 2007-01-24 09:21:18.553 SMON: Restarting fast_start parallel rollback *** 2007-01-24 11:16:17.697 Parallel Transaction recovery caught exception 12801 Parallel Transaction recovery caught error 370 *** 2007-01-24 11:16:20.885 SMON: Restarting fast_start parallel rollback Dead transaction 0x0003.028.00017d2a recovered by 1 server(s)
最后两行至为关键,Oracle通过1个Server进程进行恢复,通过查询视图V$FAST_START_TRANSACTIONS,可以发现恢复的速度加快了许多:
SQL> select usn,undoblockdone,undoblockstotal,cputime from V$FAST_START_TRANSACTIONS; USN UNDOBLOCKSDONE UNDOBLOCKSTOTAL CPUTIME ---------- --------------- ------------------- --------------- 3 1036 203328 8208 SQL> select * from V$FAST_START_SERVERS; STATE UNDOBLOCKSDONE PID XID ----------- -------------- ---------- ---------------- RECOVERING 1036 16 030028002A7D0100
UNDOBLOCKSDONE表示已经恢复的回滚段块,UNDOBLOCKSTOTAL表示需要恢复的回滚段块总量,可以看出,回滚段3在参与恢复的操作,203328中有1036块已经恢复,cpu占用了8208秒。最终再通过近3个小时的恢复,数据库完成了这次灾难性的回滚。
从v$fast_start_transactions视图我们可以看到具体信息,恢复共花费了10255秒的时间,而平均每秒数据库仅对约20个UNDO BLOCK完成了回滚:
SQL> select * from v$fast_start_transactions; USN SLT SEQ STATE UNDOBLOCKSDONE UNDOBLOCKSTOTAL CPUTIME XID RCVSERVERS --- --- ----- --------- -------------- --------------- ------- ---------------- ---------- 3 40 97578 RECOVERED 203328 203328 10255 030028002A7D0100 1
通过这个案例我们知道Oracle的并行回滚有时候并不可靠,而且的确还存在大量的Bug,从Oracle的官方网站上可以找到大量类似的案例。
SMON对于死事务执行恢复,如果事务很大,Oracle将首先尝试并行恢复,并行恢复Oracle将采用intra-transaction并行恢复,也就是使用多个并行进程恢复死事务,如果intra-transaction并行恢复失败,SMON将指定单进程进行恢复,这个恢复过程将会十分缓慢,特别是当事务很大时。在恢复期间,SMON进程还可能停止其他类别的服务,如排序段请求、实例恢复请求等,同时还可能导致查询十分缓慢(由于大量的CR回滚等),从外在看来,数据库就可能处于停顿状态。这些问题最终被定义为一个Bug,Oracle在Oracle 11g中进行了改进。
然而这种问题应该极少被遇到,做为一个DBA也应该避免陷于这样的境地,将这个案例收录于此,供大家借鉴。