一、概述
本文將給大家介紹oracle各類文件損壞的現象和應對策略,請注意所有的恢復都是基於有備份的情況,所以請開啟數據庫的日常備份。文章將從以下文件展開
a. 密碼文件
b. 參數文件
c. 控制文件
d. 數據文件(分普通表空間數據文件,其它表空間數據文件如system、sysaux、undo)
e. 日志文件(分current、active、inactive)
在正式實驗之前,我先問一個問題,上面這些文件,哪個損壞最致命?
二、環境准備
本實驗在oracle 11G歸檔模式下進行,實驗前先對數據庫做個全庫備份。
創建一個普通表空間和一些測試表
create tablespace tbs01 datafile '/u01/app/oracle/oradata/orcltest/tbs01.dbf' size 500m;
create table scott.t01 tablespace tbs01 as select * from dba_objects where rownum<=100;
RMAN> backup database; // 全庫備份
RMAN> list backup; // 查看備份
BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ --------------- 21 Full 1.14G DISK 00:01:33 17-MAR-20 BP Key: 21 Status: AVAILABLE Compressed: NO Tag: TAG20200317T133425 Piece Name: /home/oracle/backupdir/ORCLTEST_2750922031_133_1_20200317_1035293665.bkp List of Datafiles in backup set 21 File LV Type Ckp SCN Ckp Time Name ---- -- ---- ---------- --------- ---- 1 Full 1606913 17-MAR-20 /u01/app/oracle/oradata/orcltest/system01.dbf 2 Full 1606913 17-MAR-20 /u01/app/oracle/oradata/orcltest/sysaux01.dbf 3 Full 1606913 17-MAR-20 /u01/app/oracle/oradata/orcltest/undotbs01.dbf 4 Full 1606913 17-MAR-20 /u01/app/oracle/oradata/orcltest/users01.dbf 5 Full 1606913 17-MAR-20 /u01/app/oracle/oradata/orcltest/example01.dbf 6 Full 1606913 17-MAR-20 /u01/app/oracle/oradata/orcltest/tbs01.dbf BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ --------------- 22 Full 9.73M DISK 00:00:02 17-MAR-20 BP Key: 22 Status: AVAILABLE Compressed: NO Tag: TAG20200317T133602 Piece Name: /home/oracle/backupdir/c-2750922031-20200317-00 SPFILE Included: Modification time: 17-MAR-20 SPFILE db_unique_name: ORCLTEST Control File Included: Ckp SCN: 1606985 Ckp time: 17-MAR-20
三、密碼文件損壞
文件說明:密碼文件存儲的是sys密碼
模擬故障:清空該文件
echo '' > $ORACLE_HOME/dbs/orapworcltest // orcltest是該數據庫的實例名
現象:使用sys通過oracle net登錄報密碼錯誤
sqlplus sys/123456@10.40.16.120:1521/orcltest as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Tue Mar 17 13:57:52 2020 Copyright (c) 1982, 2013, Oracle. All rights reserved. ERROR: ORA-01017: invalid username/password; logon denied Enter user-name:
修復:使用自帶工具orapwd重新生成密碼文件
orapwd file=$ORACLE_HOME/dbs/orapworcltest password=123456 force=y // force=y如果原密碼文件存在,強制覆蓋
四、參數文件損壞
文件說明:這里所說的參數文件指的是spfile,該文件存儲的是實例啟動的參數和控制文件的路徑
模擬故障:清空該文件
echo '' > $ORACLE_HOME/dbs/spfileorcltest.ora
現象:修改數據庫參數時會報錯
SQL> alter system set open_cursors=400;
alter system set open_cursors=400 * ERROR at line 1: ORA-01565: error in identifying file '/u01/app/oracle/product/11.2.0/db_1/dbs/spfileorcltest.ora' ORA-27046: file size is not a multiple of logical block size Additional information: 1
修復:使用rman還原參數文件
RMAN> list backup of spfile;
BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ --------------- 22 Full 9.73M DISK 00:00:02 17-MAR-20 BP Key: 22 Status: AVAILABLE Compressed: NO Tag: TAG20200317T133602 Piece Name: /home/oracle/backupdir/c-2750922031-20200317-00 SPFILE Included: Modification time: 17-MAR-20 SPFILE db_unique_name: ORCLTEST
RMAN> restore spfile to '/home/oracle/spfileorcltest.ora' from '/home/oracle/backupdir/c-2750922031-20200317-00';
mv /home/oracle/spfileorcltest.ora /u01/app/oracle/product/11.2.0/db_1/dbs/
SQL> shutdown immediate
SQL> startup
注意在還原spfile的時候如果還原到spfile原先的位置,會報ORA-32011: cannot restore SPFILE to location already being used by the instance
所以需要還原到一個新的路徑,然后手工移過去
PS:參數文件也可以從內存中直接創建一個新的,更省事(create spfile='/home/oracle/spfileorcltest.ora' from memory;)
五、控制文件損壞
文件說明:控制文件記錄數據庫文件的信息和日志的信息等
查看控制文件
SQL> show parameter control_files
NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ control_files string /u01/app/oracle/oradata/orclte st/control01.ctl
模擬故障:將該文件清空
echo '' > /u01/app/oracle/oradata/orcltest/control01.ctl
現象:前台正常的增刪改查不受影響,但一旦出現切換日志或產生檢查點時數據庫宕機
SQL> alter system switch logfile;
alter system switch logfile * ERROR at line 1: ORA-03113: end-of-file on communication channel Process ID: 3433 Session ID: 1 Serial number: 5
數據庫alert日志
Tue Mar 17 17:39:06 2020 Errors in file /u01/app/oracle/diag/rdbms/orcltest/orcltest/trace/orcltest_ckpt_3415.trc: ORA-00202: control file: '/u01/app/oracle/oradata/orcltest/control01.ctl' ORA-27072: File I/O error ... LGWR (ospid: 3413): terminating the instance due to error 227 Tue Mar 17 17:40:37 2020 System state dump requested by (instance=1, osid=3413 (LGWR)), summary=[abnormal instance termination]. System State dumped to trace file /u01/app/oracle/diag/rdbms/orcltest/orcltest/trace/orcltest_diag_3403_20200317174037.trc Dumping diagnostic data in directory=[cdmp_20200317174037], requested by (instance=1, osid=3413 (LGWR)), summary=[abnormal instance termination]. Instance terminated by LGWR, pid = 3413
修復:使用rman還原控制文件
rman target /
RMAN> startup nomount
RMAN> restore controlfile from '/home/oracle/backupdir/c-2750922031-20200317-00';
RMAN> alter database mount;
RMAN> recover database; // 這一步其實是使用archivedlog + redolog對控制文件進行恢復
RMAN> alter database open resetlogs;
說明:a. 不要使用刪控制文件的方式去模擬該實驗,這是由於ckpt、lgwr進程已經打開了控制文件,內存中已經有了這個控制文件的鏡像,而rm命令並不能把這些進程已經打開的控制文件的句柄刪掉。所以你會發現實例並沒有掛掉。
b. 對數據庫resetlogs之后,之前的備份就作廢了,所以應該第一時間對數據庫做一個全備。
c. 可能大家也注意到了,該實驗中只有一個controlfile,當controlfile被破壞了之后,實例就掛了。如果是controlfile的多路復用,其中一個controlfile壞了數據庫又是什么影響?我這里先說下我的結論:controlfile只要有一個壞了,實例就會奔潰,同時在alert日志中會提示具體是哪個controlfile損壞,解決辦法就是復制一份好的controlfile去替換損壞的controlfile,重新啟庫即可。實驗就留給大家自己做吧。附一段我實驗的alert日志(ORA-00227: corrupt block detected in control file: (block 1, # blocks 1) ORA-00202: control file: '/u01/app/oracle/oradata/orcltest/control02.ctl')
總結:1. 控制文件恢復不會丟失任何事務,但會要求數據庫resetlogs,這將會導致之前的備份片無效,所以恢復控制文件后最好做一個全庫備份。
2. 對控制文件最好設置兩個,一個壞了還能利用另一個恢復,對數據庫的影響和恢復的時間都是最小的。
六、數據文件損壞
為了繼續實驗,請手工刪除之前所有的歸檔日志和備份文件,並對現在的數據庫做一個全備
RMAN> backup database; // 全庫備份
6.1 普通數據文件損壞
模擬故障:將該文件清空
echo '' > /u01/app/oracle/oradata/orcltest/tbs01.dbf // tbs01是一個普通表空間數據文件
現象:查詢該數據文件上的對象報錯
SQL> select * from scott.t01; // t01表在tbs01.dbf文件上
select * from scott.t01 * ERROR at line 1: ORA-01115: IO error reading block from file (block # ) ORA-01110: data file 6: '/u01/app/oracle/oradata/orcltest/tbs01.dbf' ORA-27072: File I/O error Additional information: 4 Additional information: 130
修復:先對數據文件offline,然后使用rman還原恢復,最后online
SQL> alter database datafile 6 offline;
RMAN> restore datafile 6;
RMAN> recover datafile 6;
SQL> alter database datafile 6 online;
6.2 system表空間數據文件損壞
模擬故障:將該文件清空
echo '' > /u01/app/oracle/oradata/orcltest/system01.dbf
現象:查詢數據字典報錯
SQL> select * from dba_users;
select * from dba_users * ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-01115: IO error reading block from file (block # ) ORA-01110: data file 1: '/u01/app/oracle/oradata/orcltest/system01.dbf' ORA-27072: File I/O error Additional information: 4 Additional information: 95524
修復:先關庫,然后使用rman還原恢復,最后啟庫
SQL> shutdown abort
SQL> startup mount
RMAN> restore datafile 1;
RMAN> recover datafile 1;
SQL> alter database open;
6.3 sysaux和undo表空間數據文件損壞
sysaux表空間的文件損壞處理手段與普通表空間數據文件損壞處理手段相同,undo表空間的文件損壞處理手段與system表空間數據文件損壞處理手段相同,因為undo表空間的數據文件也不能offline。限於篇幅省略實驗步驟,僅貼出文件損壞的現象。
sysaux表空間文件損壞現象:訪問sysaux表空間的對象報錯
SQL> select * from sys.WRI$_OPTSTAT_HISTHEAD_HISTORY;
ERROR: ORA-01578: ORACLE data block corrupted (file # 2, block # 986) ORA-01110: data file 2: '/u01/app/oracle/oradata/orcltest/sysaux01.dbf'
undo表空間文件損壞現象:所有修改操作全部報錯
SQL> insert into scott.t01 select * from scott.t01;
insert into scott.t01 select * from scott.t01 * ERROR at line 1: ORA-00603: ORACLE server session terminated by fatal error ORA-01578: ORACLE data block corrupted (file # 3, block # 144) ORA-01110: data file 3: '/u01/app/oracle/oradata/orcltest/undotbs01.dbf' ORA-01578: ORACLE data block corrupted (file # 3, block # 144) ORA-01110: data file 3: '/u01/app/oracle/oradata/orcltest/undotbs01.dbf' Process ID: 2835 Session ID: 20 Serial number: 85
七、日志文件損壞
7.1 inactive或active日志文件損壞
查看當前日志狀態:current-當前正在寫入的日志組,active-還未歸檔的日志組,inactive-已歸檔的日志組
SQL> select a.group#, a.member, b.status from v$logfile a, v$log b where a.group#=b.group# order by group#;
GROUP# MEMBER STATUS ---------- -------------------------------------------------- ------------ 1 /u01/app/oracle/oradata/orcltest/redo01.log INACTIVE 2 /u01/app/oracle/oradata/orcltest/redo02.log CURRENT 3 /u01/app/oracle/oradata/orcltest/redo03.log INACTIVE
模擬故障:將inactive日志文件清空
echo '' > /u01/app/oracle/oradata/orcltest/redo03.log
現象:當數據庫切換到該日志組時,數據庫並不知道磁盤上的日志文件有問題,只是將內容寫到日志文件在內存的拷貝中,等到切換的時候,日志文件落盤就會發現該日志是有問題的,然后alert日志出現報錯,不過不影響數據庫正常運行,只是以后數據庫切換日志會跳過該日志組
SQL> insert into scott.t01 select * from scott.t01; // 重復對一張表進行插入,模擬產生大量的日志
觀察alert日志
Errors in file /u01/app/oracle/diag/rdbms/orcltest/orcltest/trace/orcltest_arc0_9006.trc: ORA-00313: open failed for members of log group 3 of thread 1 ORA-00312: online log 3 thread 1: '/u01/app/oracle/oradata/orcltest/redo03.log' ORA-27048: skgfifi: file header information is invalid Additional information: 12 Master archival failure: 313
SQL> alter system switch logfile;
查看v$log,可以看到group 3一直沒有被用到
修復:將該日志文件重新初始化
SQL> alter database clear unarchived logfile group 3; // active的日志損壞也是類似處理,使用該命令后數據庫歸檔會斷,所以在恢復日志組后,應立即進行全庫備份。
7.2 current日志文件損壞
為了繼續實驗,請手工刪除之前所有的歸檔日志和備份文件,並對現在的數據庫做一個全備
RMAN> backup database; // 全庫備份
查看當前日志狀態
SQL> select a.group#, a.member, b.status from v$logfile a, v$log b where a.group#=b.group# order by group#;
GROUP# MEMBER STATUS ---------- -------------------------------------------------- ------------ 1 /u01/app/oracle/oradata/orcltest/redo01.log INACTIVE 2 /u01/app/oracle/oradata/orcltest/redo02.log INACTIVE 3 /u01/app/oracle/oradata/orcltest/redo03.log CURRENT
SQL> create table scott.t02 as select * from dba_users;
模擬故障:current日志文件清空
echo '' > /u01/app/oracle/oradata/orcltest/redo03.log
現象:前台正常的增刪改查不受影響,但一旦出現切換日志數據庫宕機
SQL> create table scott.t03 as select * from dba_users;
SQL> alter system switch logfile;
alter system switch logfile * ERROR at line 1: ORA-03113: end-of-file on communication channel Process ID: 3758 Session ID: 1 Serial number: 9
查看alert日志
Errors in file /u01/app/oracle/diag/rdbms/orcltest/orcltest/trace/orcltest_lgwr_8969.trc: ORA-00316: log 2 of thread 1, type 0 in header is not log file ORA-00312: online log 2 thread 1: '/u01/app/oracle/oradata/orcltest/redo02.log' LGWR (ospid: 8969): terminating the instance due to error 316 Instance terminated by LGWR, pid = 3458
恢復:使用不完全恢復打開
sqlplus / as sysdba
SQL> startup mount
SQL> recover database until cancel; // 不完全恢復
SQL> alter database open resetlogs; // 會發現啟庫失敗
alter database open resetlogs * ERROR at line 1: ORA-01194: file 1 needs more recovery to be consistent ORA-01110: data file 1: '/u01/app/oracle/oradata/orcltest/system01.dbf'
這個時候就需要加入隱含參數,再啟動
SQL> alter system set "_allow_resetlogs_corruption"=true scope=spfile;
SQL> shutdown abort
SQL> startup mount
SQL> recover database until cancel; // 不完全恢復
輸入cancel
SQL> alter database open resetlogs;
說明:a. 使用該方式恢復的庫,可能會造成數據的丟失,而且也並不能保證一定成功。
b. 恢復成功后,應將表全部使用expdp導出,重建庫。
c. 上面的實驗每個日志組都只有一個member,如果每個日志組有兩個member又是什么樣子呢?先說下我的結論:損壞其中任何一個member對數據庫沒什么影響,只是在切換到有member損壞的日志組時,會在alert日志中提示告警ORA-00313 ORA-00312 ORA-27048,解決辦法就是刪掉這個member,重新添加,不需要對數據庫進行重啟,實驗過程我就不展示了。所以最好是每組日志中設置2個成員。
這兒我有個疑問想不通:對inactive的日志進行破壞,數據庫切換到這個被破壞的日志時,數據庫正常寫,只是在日志切換的時候報錯,這個能理解,因為系統內存中有這個被破壞的日志之前的拷貝,所有的寫可能都是在內存中。切換的時候該日志文件就必須要落盤,所以提示報錯。而對current的日志進行破壞,數據庫也正常寫,但是在日志切換的時候數據庫直接崩了。沒弄懂這兩個為什么會有這個區別。
八、總結
1. 生產中應制定好備份策略
2. 控制文件和日志文件最好是設置大於一個成員
3. 當前日志組損壞最為致命,如果日志寫很繁忙,可以只為日志文件配置一個成員,但同時需要配置一個dataguard,方便切換
4. 此博客僅為個人理解,如有不對的地方,歡迎大家指出。