oracle RedoLog Checkpoint 和 SCN關係

 

http://blog.csdn.net/tianlesoftware/article/details/5251916

一. Redo log 作用

數據庫異常關機(比如突然斷電,shutdown abort: 它會立即關閉數據庫,等同於斷電)之後,這時已經commit的事務已經記錄到online redo log中,下次啓動數據庫時,Oracle進行恢復操作,將online redo log中的事務操作調入內存中,進行相應操作後將數據記入到數據文件中,數據操作完成。對於沒有commit而已經寫入數據文件或回退段的數據,也要進行回滾操作,將數據恢復到rollback的狀態,使數據文件和控制文件恢復到崩潰前的一致性狀態。總之,數據庫下次打開時會佔用比正常關閉更長的時間。

注意:並不是所有異常關機後,下次啓動時都可以恢復到正常狀態,異常關機容易導致壞塊的產生,這種情況下數據庫是不能正常啓動的,如果處理不當,將會導致大量數據的丟失。 具體參考我的blog:

Oracle 壞塊 總結

http://blog.csdn.net/tianlesoftware/archive/2009/12/18/5024966.aspx


Rolling Forward(前滾)
Oracle啓動實例並加載數據庫,然後通過Online Redologs中的重做日誌,重現實例崩潰前對數據庫的修改操作。在恢復過程中對於已經提交的事務,但尚未寫入數據文件的那部分數據全部寫入數據文件.


Rolling Back(回滾)

Rolling Forward之後,雖然已經提交的修改操作更改的數據都已經被寫入數據文件,但在實例崩潰時,部分未提交的事務操作的數據也被寫入到數據文件,這些事務必須被撤銷.

觸發LGWR進程的條件有: 
  1. 用戶提交 
  2. 有1/3重做日誌緩衝區未被寫入磁盤 
  3. 有大於1M的重做日誌緩衝區未被寫入磁盤 
  4. 3秒超時 
  5. DBWR 需要寫入的數據的SCN大於LGWR記錄的SCN,DBWR 觸發LGWR寫入。 

二. Checkpint(檢查點) 

 

2.1 檢查點定義
大多數關係型數據庫都採用"在提交時並不強迫針對數據塊的修改完成"而是"提交時保證修改記錄(以重做日誌的形式)寫入日誌文件"的機制,來獲得性能的優勢。

這句話的另外一種描述是:

當用戶提交事務,寫數據文件是"異步"的,寫日誌文件是"同步"的。

這就可能導致數據庫實例崩潰時,內存中的DB_Buffer 中的修改過的數據,可能沒有寫入到數據塊中。數據庫在重新打開時,需要進行恢復,來恢復DB Buffer 中的數據狀態,並確保已經提交的數據被寫入到數據塊中。檢查點是這個過程中的重要機制,通過它來確定,恢復時哪些重做日誌應該被掃描並應用於恢復。 


要了解這個檢查點,首先要知道checkpoint queue概念,檢查點發生後,觸發DBWn,CKPT獲取發生檢查點時對應的SCN,通知DBWn要寫到這個SCN爲止, DBWR寫dirty buffer 是根據 buffer 在被首次 modify的時候的時間的順序寫出,也就是 buffer被modify 的時候會進入一個queue (checkpoint queue),DBWr 就根據queue從其中批量地寫到數據文件。 由於這裏有一個順序的關係,所以 dbwr的寫的進度就是可衡量的,寫到哪個buffer的時候該buffer的首次變化時候的scn就是當前所有數據文件block的最新scn,但是由於無法適時的將dbwr的進度記錄下來,所以oracle 選擇了一些策略。 其中就包括ckpt進程的檢查點和心跳。


檢查點發生以後,CKPT進程檢查checkpoint queue(也就是髒塊鏈表)是否過長,如果是,則觸發DBWn,將一部分髒塊寫入數據文件,從而縮短checkpoint queue。

checkpoint 發生時,一方面通知dbwr進行下一批寫操作,(dbwr 寫入的時候,一次寫的塊數是有一個批量寫的隱藏參數控制的); 另一方面,oracle 採用了一個心跳的概念,以3秒的頻率將dbwr 寫的進度反應到控制文件中,也就是把dbwr當前剛寫完的dirty buffer對應的scn 寫入數據文件頭和控制文件,這就是檢查點scn。

這個3秒和增量檢查點不是一個概念,3秒只是在控制文件中,ckpt 進程去更新當前 dbwr寫到哪裏了,這個對於 ckpt 進程來說叫 heartbeat ,heartbeat是3秒一次,3秒可以看作不停的檢查並記錄檢查點執行情況(DBWR的寫進度)。


檢查點發生之後數據庫的數據文件、控制文件處於一致狀態的含義是不需要進行 介質恢復,只表示數據文件頭一致,但是並不表示數據文件內容一致,因爲數據文件內容可能在沒有發生檢查點的其它情況下的dbwr寫數據文件,這樣數據文件內容就不一致,若掉電需要進行崩潰恢復。

觸發DBWR進程的條件有: 
1.  DBWR超時,大約3秒 
2. 系統中沒有多餘的空緩衝區來存放數據 
3.  CKPT 進程觸發DBWR

2.2  Checkpoint 觸發條件


oracle8以後推出了incremental checkpoint(增量檢查點)的機制,在以前的版本里每checkpoint時都會做一個full thread checkpoint(完全檢查點),這樣的話所有髒數據會被寫到磁盤,巨大的i/o對系統性能帶來很大影響。爲了解決這個問題,oracle引入了checkpoint queue機制,每一個髒塊會被移到檢查點隊列裏面去,按照low rdb(第一次對此塊修改對應的redo block address)來排列,靠近檢查點隊列尾端的數據塊的low rba值是最小的,而且如果這些贓塊被再次修改後它在檢查點隊列裏的順序也不會改變,這樣就保證了越早修改的塊越早寫入磁盤。每隔3秒鐘ckpt會去更新控制文件和數據文件,記錄checkpoint執行的情況。

觸發CheckPoint(檢查點) 條件有很多,比如:

1. 通過正常事務處理或者立即選項關閉例程時(shutdown immediate或者Shutdown normal), 

2. 當通過設置初始化參數:

LOG_CHECKPOINT_INTERVAL,

LOG_CHECKPOINT_TIMEOUT ,

FAST_START_IO_TARGET 強制時;
3. 當數據庫管理員手動請求時:

ALter system checkpoint;
alter tablespace ... offline;


4. 每次日誌切換時;

alter system switch logfile


注意:

1. alter system switch logfile也將觸發完全檢查點的發生。
2. alter database datafile ... offline 不會觸發檢查點進程。

如果是單純的offline datafile,那麼將不會觸發文件檢查點,只有針對offline tablespace的時候纔會觸發文件檢查點,這也是爲什麼online datafile需要media recovery而online tablespace不需要。

對於表空間的offline後再online這種情況,最好做個強制的checkpoint比較好。

關於offline datafile 和tablespace 的區別也可以參考我的blog:

ALTER DATABASE 與 ALTER TABLESPACE OFFLINE的區別

http://blog.csdn.net/tianlesoftware/archive/2009/11/30/4898800.aspx

以上的觸發條件將觸發完全檢查點,促使DBWR 將檢查點時刻前所有的髒數據寫入數據文件。另外,一般正常運行期間的數據庫不會產生完全檢查點。

下面很多事件將導致增量檢查點,比如:

1. 在聯機熱備份數據文件前,要求該數據文件中被修改的塊從DB_Buffer 寫入數據文件中。所以,發出這樣的命令:
ALTER TABLESPACE tablespace_name BIGEN BACKUP & end backup; 也將觸發和該表空間的數據文件有關的局部檢查點;

2. 另外, 
ALTER TABLESPACE tablespace_name READ ONLY;
ALTER TABLESPACE tablespace_name OFFLINE NORMAL;
等命令都會觸發增量檢查點。

2.3 關於檢查點的一點具體應用討論


2.3.1.  Commit成功後,數據還會丟失嗎?


對於Oracle來說,用戶所做的DML操作一旦被提交,則先是在database buffer cache 中進行修改,同時在修改之前會將數據的前鏡像保存在回滾段中,然後將修改之前和修改之後的數據都寫入到redo log buffer中,當接收到commit命令之後,則redo log buffer開始寫redo log file ,並且記錄此時的scn,當redo log file 寫完了之後,表示這次事務提交操作已經確認被數據庫記錄了,只有當redo log file 寫成功了,纔會給用戶 Commit completed 的成功字樣。而對於Database buffer cache中的dirty buffer則會等待觸發DBWn才寫入,但是如果此時斷電,則數據已經被記錄到了redo log file中,系統在重新啓動的時候,會自動進行嵌滾和回滾來保證數據的一致。所以,只要是commit成功的了,數據不會丟失!

2.3.2. 數據庫發生一次DBWn,是否將所有buffer cache 中的dirty buffer 都寫入,還是先將髒隊列中的數據寫入? 

這話看起來有道理,但實際上,dbwr在寫的時候又不斷地在產生dirty buffer ,所以說檢查點發生的時候是期望把該時間點之前的所有髒緩衝區寫入數據文件。
所有的buffer,不在LRU list上就在dirty list上, dbwr寫入的時候,一次寫的塊數是有一個批量寫的隱藏參數控制的。
所以說要是 dbwr將 dirty list也好, lru list上的也好,要實現全部寫入,都是一個現實系統中很難存在的現象。dirty 總是在不斷的產生,dbwr總是在不斷地寫,增量檢查點發生的時候也並不意味着一定要更新數據文件頭,檢查點開始的時候只表示該次檢查點結束的時候要更新數據文件頭的話數據文件頭具有該時間點的一致性。


2.3.3. 關於檢查點等待事件:


有些事件的產生必須等待檢查點的完成,才能開始數據庫的其它操作:日誌文件切換就是其中一個事件,日誌切換必須等待檢查點完成。


log file switch (checkpoint incomplete) 這個等待事件本身也說明,日誌切換時產生的檢查點是需要等待的,這個日誌文件所對應髒塊全部寫完後,檢查點進程更新控制文件和數據頭,然後這個檢查點才能算完成。
也就是說日誌切換必須等待檢查點完成,而檢查點在等待DBWn完成。


這種等待DBWn完成的檢查點,最後一步寫入控制文件和數據文件頭的SCN,肯定是DBWn完成的最後一塊的SCN。


2.3.4. 檢查點爲什麼要等待dbwr完成後才進行切換(log switch)?


log switch時,是不能立即switch到active狀態的,log group必須等待。

active表示該log group還沒有完成歸檔(歸檔模式下)或者該log group有進行instance recovery的需要用到的日誌。所以當checkpoint發生時,如果dbwr還沒有寫完它該寫完的dirty buffers(該checkpoint時間點以前產生的dirty buffers, 靠scn判斷),則該log group處於active狀態,不會進行日誌切換,當然也不會發生日誌文件被覆蓋的問題了。


2.3.5. 如果沒有設置archive log ,在檢查點發生後,發生log switch一個輪迴,log file是否會被覆蓋掉? 


當檢查點發生後,會觸發lgwr,lgwr會把此時SCN以前在redo buffer中的所有操作寫到redo log file,同時lgwr也會觸發dbwr進程,dbwr也開始把此刻以前database buffer中的dirty buffer隊列中的操作寫入data file。
其實檢查點發生後,就是lgwr和dbwr寫buffer到磁盤文件的過程,但是兩者的讀寫速度時不同的,dbwr寫buffer到數據文件的過程相對較慢,因爲dbwr寫過程是一個隨機讀取存儲的過程。Lgwr寫buffer到redo文件的過程比dbwr要快很多,因爲lgwr是順序讀取寫入的。


由於以上lgwr和dbwr寫操作的速度不同,就產生了一個等待問題。即當lgwr
輪循一圈後,要進行日誌切換,覆蓋redo log file,但是此時dbwr還沒有寫完,那麼lgwr就會出現等待,oracle也會hang在那裏,同時alter文件中會提示一個相應的提示checkpoint not complete。等檢查點完成後數據庫自動恢復正常。
當log switch時,會觸發檢查點,標記檢查點時,DBWR要把log file中covered by the log being checkpointed的數據寫入到數據文件上,如果Dbwr沒有寫完,那麼前一個logfile是不能被覆蓋的。因此必須等檢查點完畢,也可以說是將要被覆蓋的日誌相關的數據塊全部寫入數據文件後,該日誌文件才能被覆蓋!


如果這種情況出現,alert文件中會記錄checkpoint not complete事件,這通常表明你的dbwr寫入過慢或者logfile組數過少或log file太小。

Redo Log 和Checkpoint not complete

http://blog.csdn.net/tianlesoftware/archive/2009/12/01/4908066.aspx

2.3.6. 檢查點發生時,出現日誌切換,但是dbwr還沒有寫完,是否會覆蓋redo log file,如果此時掉電,dbwr掛起,會出現丟失數據嗎?

不會覆蓋redo文件,要等待dbwr寫完才覆蓋。或者說要等待檢查點完成才覆蓋。
如果DBWn正在寫的髒塊是指對應到即將被覆蓋的那個日誌文件的,那麼,因爲在這些操作完成之前,不可能有覆蓋這件事發生,假設你預料的掉電發生了,不會有什麼問題,實例恢復時的前滾從剛纔準備覆蓋的那個日誌文件開始。

如果正在寫的髒塊是指對應到剛剛被寫滿的那個日誌文件的,肯定一時半會也寫不完,日誌切換也不會等它,如果切換成功後dbwr掛了,後面的寫髒塊操作估計也還沒完成,但是,剛寫滿的那個文件並沒有被覆蓋,也不會有任何問題。
因此不會出現數據丟失!


當一個很大的dml發生時,用戶在commit後,需要將redo log buffer中的髒數據寫入redo log file中。如果在寫的過程中,發現一個redo log file寫不下的話,需要寫另外一個redo log file,這時應該觸發checkpoint,接着觸發DBWn,將髒數據寫入datafile,這時發生掉電,導致DBWR失敗。這時其實就可以說commit失敗了。以上所述其實就是commit沒有提交成功。

2.3.7. alter systen switch logfile會觸發完全檢查點;但是爲什麼,日誌切換以後檢查點只能記錄到上一次歸檔日誌產生的時間呢?而不是現在歸檔日誌產生的時間呢?


因爲這時的checkpoint enqueue隊列中,也就是髒塊隊列中髒塊還不夠多,還不足以觸發DBWn寫髒塊。所以,內存裏需要寫入的髒塊所對應的redo還存在於上一個redo log裏,這時你去看該redo log的status爲active。

我們可以通過一下語句查看相關信息:
SQL> select * from x$kccrt;

三. SCN(system change number)

3.1 SCN 定義:

SCN是當Oracle數據更新後,由DBMS自動維護去累積遞增的一個數字。 當一個事務commit時,LGWR會將log buffer寫入redo log file,同時也會將該事務的 SCN同步寫入到redo log file內(wait-until-completed)。因此當你commit transaction時, 在成功的訊息返回之前,LGWR必須先完整的完成上述行爲之後,否則你是看不到提交成功的響應訊息。


我們可以查詢目前系統最新的SCN
select dbms_flashback.get_system_change_number from dual;


可以理解的,這裏返回的SCN,也是目前redo log file最新的SCN紀錄。 因爲commit後的交易纔會有SCN,而一旦commit就會立刻寫入redo log file中。

3.2 CHECKPOINT 和 SCN 的關連

checkpoint發生的目的就是要把儲存在buffer內的已提交的事務寫回disk,否則一旦發生crash,需要進行recovery時,你就必須花很多的時間從redo log file內最後的SCN交易開始進行recovery,這樣在商業應用上是很浪費時間和沒有效率的。


重點在於當commit一個事務時,只會立刻將redo buffer寫入redo log file內,但是並不會馬上將該update後的block(dirty block)同步寫回disk datafile中,這是爲了減少過多disk IO的考慮,所以採取batch的方式寫入。


When a checkpoint occurs, Oracle must update the headers of all datafiles to record the details of the checkpoint. This is done by the CKPT process. The CKPT process does not write blocks to disk; DBWn always performs that work.


在shutdown normal or shutdown immediate下,也就是所謂的clean shutdown,checkpoint也會自動觸發,並且把SCN紀錄寫回。 

當發生checkpoint時,會把SCN寫到四個地方去。

三個地方於control file內,一個在datafile header。


Control file三個地方爲


1.System checkpoint SCN ===========> (SYSTEM CHECKPOINT SCN in control file)
SQL> select checkpoint_change# from v$database;
CHECKPOINT_CHANGE#
--------------------
292767
2.Datafile checkpoint SCN ===============> (DATAFILE CHECKPOINT SCN in control file)
SQL> select name,checkpoint_change#
from v$datafile where name like '%users01%';
NAME CHECKPOINT_CHANGE#
----------------------------------- --------------------
/u02/oradata/OMFD1/users01.dbf 292767
3.Stop SCN ======================> (STOP SCN in control file)
SQL> select name,last_change#
from v$datafile where name like '%users01%';
NAME LAST_CHANGE#
----------------------------------- ------------
/u02/oradata/OMFD1/users01.dbf


正常datafile在read-write mode下  last_change#一定是NULL


另外一個地方在datafile header內


4.Start SCN ================================> (DATAFILE HEADER)
SQL> select name,checkpoint_change#
from v$datafile_header where name like '%users01%';
NAME CHECKPOINT_CHANGE#
----------------------------------- --------------------
/u02/oradata/OMFD1/users01.dbf 292767

3.3 相關問題


3.3.1 爲什麼儲存在CONTROL FILE中要分爲兩個地方(SYSTEM CHECKPOINT SCN,DATAFILE CHECKPOINT SCN) ?

當你把一個tbs設爲read-only時,他的SCN會凍結停止,此時DATAFILE CHECKPOINT SCN是不會再遞增改變的, 但是整體的SYSTEM CHECKPOINT SCN卻仍然會不斷遞增前進。
所以,這就是爲什麼需要分別在兩個地方儲存SCN。

3.3.2 正常shutdown database後,SCN會發生什麼變化?
我們可以把數據庫開在mount mode
select checkpoint_change# from v$database;
CHECKPOINT_CHANGE#
--------------------
293184
select name,checkpoint_change#,last_change# from v$datafile where name like '%user%';
NAME CHECKPOINT_CHANGE# LAST_CHANGE#
----------------------------------- -------------------- --------------
/u02/oradata/OMFD1/users01.dbf 293184 293184
可以看到儲存在control file中的三個SCN位置都是相同,注意此時的stop scn不會是NULL,而是等於start scn


我們來查詢datafile header SCN:
select name,checkpoint_change# from v$datafile_header where name like '%users01%';
NAME CHECKPOINT_CHANGE#
----------------------------------- --------------------
/u02/oradata/OMFD1/users01.dbf 293184


當clean shutdown 時,checkpoint會進行,並且此時datafile的stop scn和start scn會相同。 等到我門開啓數據庫時,Oracle檢查datafile header中的start scn和存於control file中的datafile的scn是否相同, 如果相同,接着檢查start scn和stop scn是否相同,如果仍然相同,數據庫就會正常開啓,否則就需要recovery... 等到數據庫開啓後,儲存在control file中的stop scn就會恢復爲NULL值,此時表示datafile是open在正常模式下了。


如果不正常SHUTDOWN (shutdown abort),則mount數據庫後,你會發現stop scn並不是等於其它位置的scn, 而是等於NULL,這表示Oracle在shutdown時沒有進行checkpoint,下次開機必須進行crash recovery。


crash recovery
必須先進行roll forward(從redo log file中從目前的start SCN開始,重做後面的已提交之交易)。再從roll back segment 做rollback未完成(dead transaction)交易。檢驗controlfile中的SCN會等於datafile header的SCN


select 'controlfile' "SCN location",name,checkpoint_change#
from v$datafile where name like '%users01%'
union
select 'file header',name,checkpoint_change#
from v$datafile_header where name like '%users01%';
SCN location NAME CHECKPOINT_CHANGE#
-------------- ----------------------------------- --------------------
controlfile /u02/oradata/OMFD1/users01.dbf 293188
file header /u02/oradata/OMFD1/users01.dbf 293188


3.3.3 crash recovery 和media recovery 的比較


啓動數據庫時,如果發現STOP SCN = NULL,表示需要進行crash recovery;啓動數據庫時,如果發現有datafile header的START SCN 不等於儲存於CONTROLFILE的DATAFILE SCN,表示需要進行Media recovery


STOP SCN equal NULL ==> NEED CRASH RECOVERY
DATAFILE HEADER START SCN not equal CONTROLFILE SCN ==> NEED MEDIA RECOVERY


3.3.4 RECOVERY DATABASE 兩種常見問題
1) RECOVER DATABASE UNTIL CANCEL ==> OPEN DATABASE RESETLOG
==> DATAFILE HEADER SCN一定會小於CONTROLFILE的DATAFILE SCN


如果你有進行RESTORE DATAFILE,則該RESTORE的DATAFILE HEADER SCN一定會小於目前CONTROLFILE的DATAFILE SCN,此時會無法開啓數據庫,必須進行media recovery。 重做archive log直到該datafile header的SCN=current scn


restore datafile後,可以mount database然後去檢查controlfile and datafile header的SCN


select 'controlfile' "SCN location",name,checkpoint_change#
from v$datafile where name like '%users01%'
union
select 'file header',name,checkpoint_change#
from v$datafile_header where name like '%users01%';


SCN location NAME CHECKPOINT_CHANGE#
-------------- ----------------------------------- --------------------
controlfile /u02/oradata/OMFD1/users01.dbf 313551
file header /u02/oradata/OMFD1/users01.dbf 313401


2) RECOVER DATABASE UNTIL CANCEL USING BACKUP CONTROLFILE; ===> OPEN DATABASE RESETLOG


==> DATAFILE HEADER SCN一定會大於CONTROLFILE的DATAFILE SCN


如果只是某TABLE被DROP掉,沒有破壞數據庫整體數據結構,還可以用NCOMPLETE RECOVERY解決 如果是某個TABLESPACE OR DATAFILE被DROP掉,因爲檔案結構已經破壞,目前的CONTROL FILE內已經沒有 該DATAFILE的信息,就算你只RESTORE DATAFILE然後進行INCOMPLETE RECOVERY也無法救回被DROP的DATA FILE。


只好RESOTRE 之前備份的CONTROL FILE(裏頭被DROP DATAFILE Metadata此時還存在),不過RESTOREC CONTROL FILE後 此時Oracle會發現CONTROL FILE內的SYSTEM SCN會小於目前的DATAFILE HEADER SCN,也不等於目前儲存於LOG FILE內的SCN, 此時就必須使用RECOVER DATABASE UNTIL CANCEL USING BACKUP CONTROLFILE到DROP DATAFILE OR DROP TABLESPACE之前的SCN。

另一種特殊狀況就是,萬一不幸地所有CONTROL FILE都遺失了,也必須用這種方式救回,所以請做MULTIPLEXING。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章