oracle異機恢複測試
- 2019 年 10 月 3 日
- 筆記
(一)問題背景
最近在生產環境中,開發人員誤操作,使用truncate將oracle資料庫某個表的數據全部刪除了,在刪除之後,開發人員發現自己闖禍了,於是聯繫值班的DBA進行緊急數據恢復。
經過分析,表被truncate後,使用一般的閃回表、閃回查詢、閃回事物等方法,是不可能將數據找回來的,可以使用閃回資料庫、閃回數據歸檔的方法來進行恢復,但是通常在生產環境中,都不會開啟這2個特性,所以剩下的只有使用RMAN進行數據恢復了。
對於使用RMAN進行數據恢復,可以在生產環境上直接進行,也可以恢復到其它機器上。
- 直接在生產環境上恢復:①需要停止生產資料庫;②資料庫需要保持一致性,比如說,我需要將資料庫恢復到12:00,那麼資料庫中其他表的數據也將恢復到12點,有可能會丟失較多數據;③如果恢復過程中出現其它問題也比較麻煩,耽誤了生產業務執行。
- 恢復到其它機器上:②不需要停生產庫;②僅僅丟失truncate表的數據,比如說,我需要將資料庫恢復到12:00,那麼我只需將整個庫在測試環境上恢復到12點,再將我們丟失表的數據通過DB_LINK或數據泵等方式恢復到生產環境,生產環境其它表的數據是不受影響的;③恢復失敗,並不會影響到生產庫。
所以,經過一番考慮,決定將資料庫恢復到其它機器上,然後再將truncate表的數據導回到生產環境。
此次恢復操作是同事做的,在恢復過程中,由於流程不熟悉,查資料耽誤了一些時間(大約20分鐘),雖然資料庫恢復完成了,但沒有達到快速恢復的要求。思考了一下,假如自己來做,能否在開發人員焦急等待的情況下,自己毫不慌亂、快速穩定的完成資料庫恢復?確實是不可能的。一方面恢複流程不熟練,畢竟資料庫恢復操作一年也不可能遇到幾次,另一方面在用戶及開發人員催促的情況下,DBA也很容易慌張,影響效率。因此最好的方式是:提前演練、寫好操作流程。當故障發生時,照著文檔操作,以最快的速度恢復生產。
(二)環境準備
生產環境 | 異機環境 | |
作業系統 | RedHat6.7 | RedHat6.7 |
資料庫版本 | 11.2.0.4(RAC,2個節點) | 11.2.0.4(單節點) |
db_name | prodb | prodb |
instance_name | prodb1、prodb2 | prodb |
資料庫安裝情況 | 安裝GI+資料庫軟體+創建資料庫 | 安裝GI+資料庫軟體 (不用創建資料庫) |
磁碟組資訊 | OCR : 3*1GB,normal DATA :3*5GB,external ARCH : 1*5GB,external |
OCR : 3*1GB,normal DATA :3*5GB,external ARCH : 1*5GB,external |
備註:為了方便,在後續環境中,生產環境資料庫簡稱「生產庫」,異機環境的資料庫簡稱「測試庫」。
(三)測試方案
(四)詳細執行過程
(4.1)創建測試表
這裡創建了2個測試表,作用分別如下:
lijiaman.test01:用於做truncate測試的表,最後在測試庫需要進行test01表的恢復。
lijiaman.test02:用於模擬資料庫事務,對該表不斷執行插入操作,使得資料庫產生大量歸檔日誌。
(Ⅰ)表test01,一共有14筆數據。
SQL> CREATE TABLE test01 AS SELECT * FROM scott.emp; Table created SQL> select count(*) from test01; COUNT(*) ---------- 14
(ⅠⅠ)表test02,持續往裡面寫入數據
--創建表test02 create table test02 ( col1 number, col2 number, col3 varchar2(30), col4 date, col5 varchar2(100) ); --創建隨機數據插入存儲過程 create or replace procedure p_insert_test02 is BEGIN FOR i IN 1..10000 LOOP insert into test02(col1,col2,col3,col4,col5) values ((select round(dbms_random.value(1, 100000000)) from dual), (select round(dbms_random.value(10000, 100000000)) from dual), (select dbms_random.string('a', 25) from dual), sysdate, (select dbms_random.string('a', 85) from dual)); commit; END LOOP; end p_insert_test02; --制定job,沒隔30s執行一次上面的存儲過程 declare job1 number; begin sys.dbms_job.submit(job => job1, what => 'p_insert_test02;', next_date => sysdate, interval => 'sysdate + 30/(1440*60)'); --每隔30s向test02表插入10000筆隨機數據 commit; end; /
(4.2)對資料庫進行完全備份
rman target / RMAN> run { allocate channel c1 type disk; allocate channel c2 type disk; sql' alter system archive log current'; backup database format '/databaseBackup/full_db_%U'; sql' alter system archive log current'; backup archivelog all format '/databaseBackup/archlog_%U'; backup current controlfile format '/databaseBackup/controlfile_%U'; backup spfile format '/databaseBackup/spfile_%U'; release channel c1; release channel c2; }
生成的備份集如下:
[oracle@node1 databaseBackup]$ ls -l
total 4136752
-rw-r—– 1 oracle asmadmin 1451128832 Sep 27 19:27 archlog_0iucr7hg_1_1
-rw-r—– 1 oracle asmadmin 1462116352 Sep 27 19:27 archlog_0jucr7hh_1_1
-rw-r—– 1 oracle asmadmin 1406464 Sep 27 19:27 archlog_0kucr7lr_1_1
-rw-r—– 1 oracle asmadmin 18841600 Sep 27 19:28 controlfile_0lucr7m2_1_1
-rw-r—– 1 oracle asmadmin 805953536 Sep 27 19:25 full_db_0eucr7f7_1_1
-rw-r—– 1 oracle asmadmin 477528064 Sep 27 19:25 full_db_0fucr7f7_1_1
-rw-r—– 1 oracle asmadmin 18841600 Sep 27 19:25 full_db_0gucr7h3_1_1
-rw-r—– 1 oracle asmadmin 98304 Sep 27 19:25 full_db_0hucr7ha_1_1
-rw-r—– 1 oracle asmadmin 98304 Sep 27 19:28 spfile_0mucr7m5_1_1
確認歸檔日誌備份情況,可以看到,本次全備份歸檔日誌備份到了thread1:57,thread2:48。
RMAN> list archivelog all;
List of Archived Log Copies for database with db_unique_name PRODB
=====================================================================
Key Thrd Seq S Low Time
——- —- ——- – ———
3 1 6 A 24-SEP-19
Name: +ARCH/prodb/archivelog/2019_09_24/thread_1_seq_6.258.1019832847
……
100 1 57 A 27-SEP-19
Name: +ARCH/prodb/archivelog/2019_09_27/thread_1_seq_57.355.1020108489
1 2 1 A 24-SEP-19
Name: +ARCH/prodb/archivelog/2019_09_24/thread_2_seq_1.256.1019830885
……
80 2 48 A 24-SEP-19
Name: +ARCH/prodb/archivelog/2019_09_24/thread_2_seq_48.335.1019838555
(4.3)資料庫正常運行,產生大量歸檔
由於日誌序列號是遞增的(以resetlogs打開資料庫例外),因此查詢每個實例上生成的最大日誌即可
SELECT * FROM (SELECT thread#, SEQUENCE#, NAME, ROW_NUMBER() OVER(PARTITION BY thread# ORDER BY SEQUENCE# DESC) rn FROM V$ARCHIVED_LOG) WHERE rn=1;
結果為:
即thread1上的歸檔日誌最大序列號為67,thread2上的歸檔日誌最大序列號為48(這裡因為個人電腦開較多虛擬機太卡,所以只開了節點1,節點2就沒有日誌生成,並不影響本次實驗結果的準確性)。
(4.4)模擬test01表被truncate,記下時間
SQL> select sysdate from dual; SYSDATE ------------------- 2019-09-27 19:37:31 SQL> SQL> truncate table test01; Table truncated.
(4.5)資料庫正常運行,產生大量歸檔
上一次備份到了sequence=57的日誌,上一次備份後又生成了25個日誌,這裡生成大量日誌是為了模擬生產資料庫這次交易的情況。
(4.6)開發人員發現表數據被truncate
開發人員發現程式報錯,查看錶test01,發現數據全沒了,開發人員確認數據被自己刪除(假設)。
(4.7)DBA執行異機恢復
思路整理:
本次恢復,需要將test01表恢復到truncate之前,我們需要有執行truncate操作之前的資料庫全備和歸檔備份。第一次全備歸檔日誌文件之備份到了thread1=57,thread2=48,在執行全被之後,又生成了許多的日誌文件,我們要將資料庫恢復到truncate之前(這裡以我們記錄的時間2019–09–27 19:37:31 為恢復點),那麼我們還需要新的日誌來做恢復,需要的日誌如下:
thread1:日誌57~67肯定需要,日誌67~82不一定需要;
thread2:由於節點未開啟,不需要日誌來做恢復。
step1:將生產庫的備份集傳到測試庫
[oracle@node1 databaseBackup]$ scp * 192.168.10.66:/databaseBackup/
step2:對恢復需要的歸檔日誌進行再次備份,得到缺少的歸檔日誌
run { allocate channel c1 type disk; sql' alter system archive log current'; backup archivelog all format '/databaseBackup/archlog_20190927_%U'; release channel c1; }
得到的歸檔日誌備份集如下:
-rw-r—– 1 oracle asmadmin 1621476864 Sep 27 20:50 archlog_20190927_0nucrcd2_1_1
-rw-r—– 1 oracle asmadmin 1643560960 Sep 27 20:51 archlog_20190927_0oucrcg5_1_1
-rw-r—– 1 oracle asmadmin 1581030912 Sep 27 20:53 archlog_20190927_0pucrcjj_1_1
傳送到備庫上
[oracle@node1 databaseBackup]$ scp archlog_20190927_0* 192.168.10.66:/databaseBackup/
step3:根據生產庫的pfile,構造一個測試庫的pfile
[oracle@test dbs]$ pwd /u01/app/oracle/product/11.2.0/db_1/dbs [oracle@test dbs]$ vim init initprodb.ora # 添加如下資訊 audit_file_dest='/u01/app/oracle/admin/prodb/adump' audit_trail='db' compatible='11.2.0.4.0' control_files='+DATA/prodb/controlfile/current.260.1019830577' db_block_size=8192 db_create_file_dest='+DATA' db_domain='' db_name='prodb' diagnostic_dest='/u01/app/oracle' dispatchers='(PROTOCOL=TCP) (SERVICE=prodbXDB)' enable_ddl_logging=TRUE log_archive_dest_1='LOCATION=+arch' log_archive_format='%t_%s_%r.dbf' open_cursors=300 pga_aggregate_target=399507456 processes=200 remote_login_passwordfile='exclusive' sessions=225 sga_target=1199570944 prodb.undo_tablespace='UNDOTBS1' [oracle@test dbs]$ ls hc_prodb.dat hc_testdb1.dat hc_testdb.dat init.ora initprodb.ora lkTESTDB
創建pfile裡面涉及到的路徑:
[oracle@test ~]$ mkdir -p /u01/app/oracle/admin/prodb/adump
step4:將備庫啟動到nomount狀態
[oracle@test ~]$ export ORACLE_SID=prodb [oracle@test ~]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Fri Sep 27 20:58:15 2019 Copyright (c) 1982, 2013, Oracle. All rights reserved. Connected to an idle instance. SQL> startup nomount; ORACLE instance started. Total System Global Area 1202556928 bytes Fixed Size 2252704 bytes Variable Size 402653280 bytes Database Buffers 788529152 bytes Redo Buffers 9121792 bytes SQL>
step5:將資料庫添加到HA中,以便可以使用ASM存儲
[oracle@test ~]$ srvctl add database -d prodb -o /u01/app/oracle/product/11.2.0/db_1
step6:恢復控制文件,修改pfile文件,重新啟動資料庫到mount狀態
RMAN> restore controlfile from "/databaseBackup/controlfile_0lucr7m2_1_1";
注意:此時存在一個問題,我們在構造pfile文件的時候,裡面填寫了控制文件的位置,這個位置是生產庫上的位置,我們執行控制文件恢復後,需要對參數文件中的control_files參數進行修改,修改方法如下:
–首先,確認contril file在asm中的位置,
ASMCMD> pwd +data/prodb/controlfile ASMCMD> ls -lt Type Redund Striped Time Sys Name CONTROLFILE UNPROT FINE SEP 27 21:00:00 Y current.256.1020114329
–接下來,修改pfile文件的control_files參數
[oracle@test ~]$ cd $ORACLE_HOME/dbs [oracle@test dbs]$ vim initprodb.ora # 改control_files位置 control_files='+data/prodb/controlfile/current.256.1020114329'
–重啟資料庫到mount狀態
[oracle@test ~]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Fri Sep 27 21:17:26 2019 Copyright (c) 1982, 2013, Oracle. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, Automatic Storage Management, OLAP, Data Mining and Real Application Testing options SQL> shutdown immediate ORA-01507: database not mounted ORACLE instance shut down. SQL> startup mount ORACLE instance started. Total System Global Area 1202556928 bytes Fixed Size 2252704 bytes Variable Size 402653280 bytes Database Buffers 788529152 bytes Redo Buffers 9121792 bytes Database mounted. SQL>
step7:註冊新的歸檔日誌備份集到備庫的控制文件中
RMAN> catalog backuppiece "/databaseBackup/archlog_20190927_0nucrcd2_1_1"; RMAN> catalog backuppiece "/databaseBackup/archlog_20190927_0oucrcg5_1_1"; RMAN> catalog backuppiece "/databaseBackup/archlog_20190927_0pucrcjj_1_1";
step8:恢復資料庫到truncate之前
RMAN>SQL"ALTER SESSION SET NLS_LANGUAGE=''AMERICAN''"; RMAN>SQL"ALTER SESSION SET NLS_DATE_FORMAT=''YYYY-MM-DD HH24:MI:SS''"; RUN{ SET UNTIL TIME '2019-09-27 19:37:31'; RESTORE DATABASE; RECOVER DATABASE; }
step9:確認數據是已經否恢復回來
--先以只讀方式打開資料庫,如果有問題,還可以重新執行恢復 SQL> alter database open read only; Database altered. --確認數據是否找回來 SQL> select count(*) from lijiaman.test01; COUNT(*) ---------- 14
step10:如果沒問題,關閉資料庫,以resetlogs方式打開
SQL> shutdown immediate; Database closed. Database dismounted. ORACLE instance shut down. SQL> startup mount ORACLE instance started. Total System Global Area 1202556928 bytes Fixed Size 2252704 bytes Variable Size 402653280 bytes Database Buffers 788529152 bytes Redo Buffers 9121792 bytes Database mounted. SQL> alter database open resetlogs; Database altered.
恢復完成。
(4.8)將恢復的數據導入到生產環境
可以使用expdp/impdp或者是dblink將數據從測試庫導入到生產庫中。
【完】