1. 程式人生 > >Oracle - 各類檔案損壞處理辦法(附實驗步驟)

Oracle - 各類檔案損壞處理辦法(附實驗步驟)

一、概述

本文將給大家介紹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/[email protected]: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
可以看到ckpt這個程序最先發現控制檔案損壞了,例項之後被lgwr程序殺掉。可能大家在做實驗的時候發現例項是被ckpt殺掉,這也是有可能的,反正可以肯定的一點是,例項最後肯定會掛掉

修復:使用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. 此部落格僅為個人理解,如有不對的地方,歡迎大家指