1. 程式人生 > 其它 >關於Oracle資料恢復的兩個臨界點(r5筆記第42天)

關於Oracle資料恢復的兩個臨界點(r5筆記第42天)

有的網友對我之前寫的一篇技術博文中的描述提出了疑問,http://blog.itpub.net/23718752/viewspace-1436965/ 其中的主要意思是:oracle中採用了undo+redo機制來作為資料恢復的基石,資料的恢復是通過前後臺結合來實現的,在快取級別,通過dbwr,能夠把修改後的資料塊刷入資料檔案,這是一個非同步的過程,不會因為發生資料變更就馬上寫入資料檔案,同時存在log buffer,能夠通過log buffer生成redo日誌,最後通過lgwr把這部分變更刷到redo 日誌,在這個過程中lgwr負責了保持資料完整性的任務,保證了資料不會丟失。 這句話再濃縮一下就是Oracle能夠保證對於commit操作的資料都能夠成功恢復。 今天可以通過兩個特殊的場景來解釋一下。 場景1:模擬Oracle ACID的異常情況,事務已經提交,但是redo log buffer還沒有寫到磁碟

第一個場景就是把lgwr寫入redo的操作影響放大,操作時間延長。這個可以參考Jonathan Lewis的部落格。https://jonathanlewis.wordpress.com/2011/08/19/redo-2/ 這個場景被稱為模擬Oracle ACID的異常情況,事務已經提交,但是redo log buffer還沒有寫到磁碟.我們來看看再下結論。 window #1: --開啟一個視窗1,然後建立一個臨時表t1 create table t1(n1 number); insert into t1 values(1); commit; 然後通過v$process查到對應的LGWR pid n1@TEST11G> select v$process.pid from v$process where pname='LGWR'; PID ---------- 11
window #2 --開啟視窗2,開啟oradebug,繫結到lgwr上 sys@TEST11G> oradebug setorapid 11 Oracle pid: 11, Unix process pid: 11767, image: oracle@oel1 (LGWR) sys@TEST11G>oradebug suspend Statement processed. window #1--然後回到視窗1,做一個dml操作,commit n1@TEST11G> update t1 set n1 = 2; 1 row updated. n1@TEST11G> commit;
這個時候commit操作會一直hang在那兒 window #3 --開啟第3個視窗,然後檢視是否更新後的值已經可以成功檢視。 sys@TEST11G> select count(*)from n1.t1; COUNT(*) ---------- 2 1 row selected. 這個時候我們馬上做類似斷電的場景,shutdown abort sys@TEST11G> shutdown abort ORACLE instance shut down. 這個時候如果觀察第一個視窗,會發現下面的錯誤,可以得知對應的session已經被強制釋放了。 n1@TEST11G> commit; ERROR: ORA-03114: not connected to ORACLE commit * ERROR at line 1: ORA-03113: end-of-file on communication channel Process ID: 15180 Session ID: 125 Serial number: 84 然後我們重啟資料庫 idle> startup ORACLE instance started. Total System Global Area 435224576 bytes Fixed Size 1337044 bytes Variable Size 272632108 bytes Database Buffers 155189248 bytes Redo Buffers 6066176 bytes Database mounted. Database opened. 這個時候再檢視資料,就會發現更新後的值已經丟失了。 idle> select *from n1.t1; N1 ---------- 1 1 row selected. 對於這個問題,網上大家也是各有所見,有的說commit沒有成功返回,就不算是一個完整的事務,沒有恢復是可以理解的。有的說,這個是Oracle對於資料恢復的一個灰色地帶。 我的意見是首先這是一個測試,把整個過程放慢,影響放大了,整個過程處於一個快要提交但是還沒有提交的邊界。這部分內容還是沒有寫入redo中的。只是從快取中完成了整個資料變更的過程。 commit在這個放慢的臨界點沒有完成,嚴格意義上應該不屬於一個完整的事務。 上面這個案例是通過debug的方式來做的,我們來用另外一個場景來模擬一下,看看實際中可能碰到的場景如果出現類似問題,redo是否依舊可靠。 場景2:模擬Oracle 歸檔滿的臨界點,事務是否依然能夠成功提交,成功恢復 我們來模擬在歸檔日誌滿的時候,無法再寫入redo,依舊可以成功commit,但是資料是否能夠成功恢復的案例。 我們在測試環境簡單模擬一下歸檔滿的臨界點,檢視磁碟空間,歸檔所在的掛載點還有6G的可用空間。 [ora11g@oel1 archivelog]$ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda3 30G 23G 6.0G 79% /u02 none 690M 104K 690M 1% /var/lib/xenstored 我們來使用dd來建立一些dummy檔案。 [ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=5000 of=direct_5000M 5000+0 records in 5000+0 records out 5242880000 bytes (5.2 GB) copied, 224.21 seconds, 23.4 MB/s real 3m44.222s user 0m0.024s sys 0m20.317s 建立後再逐步縮小範圍。 [ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=1000 of=direct_1000M [ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=100 of=direct_100M 最後發現空間都被佔用完了。

[ora11g@oel1 archivelog]$ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda3 30G 29G 0 100% /u02 直到沒有空間可用我們才收手。 [ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=10 of=direct_10M dd: writing `direct_10M': No space left on device 1+0 records in 0+0 records out 0 bytes (0 B) copied, 0.000909 seconds, 0.0 kB/s 最後生成的dd檔案如下: -rw-r----- 1 ora11g dba 33485824 May 20 15:30 1_4_879784710.dbf -rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M -rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M -rw-r--r-- 1 ora11g dba 104603648 May 20 15:38 direct_100M -rw-r--r-- 1 ora11g dba 0 May 20 15:39 direct_10M

使用sqlplus報出下面的錯誤,這樣我們就可以開始這個臨界點的測試了。 sys@TEST11G> conn n1/n1 ERROR: ORA-00257: archiver error. Connect internal only, until freed. sys@TEST11G> create table aa as select *from cat; Table created. sys@TEST11G> insert into aa select *from aa; 4856 rows created. sys@TEST11G> commit; Commit complete. sys@TEST11G> insert into aa select *from aa; 9712 rows created. sys@TEST11G> commit; Commit complete. sys@TEST11G> select count(*)from aa; COUNT(*) ---------- 19424 可以看到這個過程中還是能夠成功commit資料的。查取更新都可以使用順利完成。 可以再開一個視窗執行alter system switch logfile做幾個日誌重新整理。發現這個時候日誌重新整理也hang住了。 看看alert日誌,發現已經提示空間不夠,無法生成歸檔日誌了。 Wed May 20 15:43:59 2015 Errors in file /u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc: ORA-19504: failed to create file "/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf" ORA-27044: unable to write the header block of file Linux Error: 28: No space left on device Additional information: 3 ARC1: Error 19504 Creating archive log file to '/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf' ARCH: Archival stopped, error occurred. Will continue retrying Non critical error ORA-00001 caught while writing to trace file "/u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc" Error message: Writing to the above trace file is disabled for now on... ORACLE Instance TEST11G - 這個時候我們繼續模擬一個斷電場景shutdown abort. 原有的日誌重新整理也會自動終止。 ERROR: ORA-03114: not connected to ORACLE alter system switch logfile * ERROR at line 1: ORA-03113: end-of-file on communication channel Process ID: 9686 Session ID: 125 Serial number: 480

如果這個時候啟動到open階段就會自動停止,原因就是歸檔空間的問題。 我們做一個小改動。騰出一小部分空間來。 [ora11g@oel1 archivelog]$ rm direct_100M 然後再次嘗試啟動資料庫就沒有問題了 idle> alter database open; Database altered. 這個時候檢視歸檔路徑下,會發現已經生成了3個歸檔文件 -rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M -rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M -rw-r--r-- 1 ora11g dba 0 May 20 15:39 direct_10M -rw-r----- 1 ora11g dba 2048 May 20 15:55 1_6_879784710.dbf -rw-r----- 1 ora11g dba 204800 May 20 15:55 1_5_879784710.dbf -rw-r----- 1 ora11g dba 1808384 May 20 15:55 1_7_879784710.dbf 這個時候發現對於這些資訊變更已經成功重新整理到了歸檔中。這樣就為資料恢復提供了強有力的基石,保證了資料在commit成功的情況下能夠成功恢復。