checkpoint說明

檢查點SCN深入研究

一、檢查點概述 
大多數關係型數據庫都採用"在提交時並不強迫針對數據塊的修改完成"而是"提交時保證修改記錄(以重做日誌的形式)寫入日誌文件"的機制,來獲得性能的優勢。這句話的另外一種描述是:當用戶提交事務,寫數據文件是"異步"的,寫日誌文件是"同步"的。這就可能導致數據庫實例崩潰時,內存中的DB_Buffer 中的修改過的數據,可能沒有寫入到數據塊中。數據庫在重新打開時,需要進行恢復,來恢復DB Buffer 中的數據狀態,並確保已經提交的數據被寫入到數據塊中。檢查點是這個過程中的重要機制,通過它來確定,恢復時哪些重做日誌應該被掃描並應用於恢復。
要了解這個檢查點,首先要知道checkpoint queu概念,檢查點發生後,觸發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寫數據文件,這樣數據文件內容就不一致,若掉電需要進行崩潰恢復。
二、觸發的條件
這裏需要明白兩個概念"完全檢查點和增量檢查點"的區別。
增量檢查點(incremental checkpoint)
oracle8以後推出了incremental checkpoint的機制,在以前的版本里每checkpoint時都會做一個full thread checkpoint,這樣的話所有髒數據會被寫到磁盤,巨大的i/o對系統性能帶來很大影響。爲了解決這個問題,oracle引入了checkpoint queue機制,每一個髒塊會被移到檢查點隊列裏面去,按照low rdb(第一次對此塊修改對應的redo block address)來排列,靠近檢查點隊列尾端的數據塊的low rba值是最小的,而且如果這些贓塊被再次修改後它在檢查點隊列裏的順序也不會改變,這樣就保證了越早修改的塊越早寫入磁盤。每隔3秒鐘ckpt會去更新控制文件和數據文件,記錄checkpoint執行的情況。
在運行的Oracle 數據中,有很多事件、條件或者參數來觸發檢查點。比如
當已通過正常事務處理或者立即選項關閉例程時;(shutdown immediate或者Shutdown normal;)
當通過設置初始化參數LOG_CHECKPOINT_INTERVAL、LOG_CHECKPOINT_TIMEOUT 和FAST_START_IO_TARGET 強制時;
當數據庫管理員手動請求時;(ALter system checkpoint)
alter tablespace ... offline;
每次日誌切換時;(alter system switch logfile)
需要說明的是,alter system switch logfile也將觸發完全檢查點的發生。
alter database datafile ... offline不會觸發檢查點進程。
如果是單純的offline datafile,那麼將不會觸發文件檢查點,只有針對offline tablespace的時候纔會觸發文件檢查點,這也是爲什麼online datafile需要media recovery而online tablespace不需要。
對於表空間的offline後再online這種情況,最好做個強制的checkpoint比較好。
  上面幾種情況,將觸發完全檢查點,促使DBWR 將檢查點時刻前所有的髒數據寫入數據文件。
另外,一般正常運行期間的數據庫不會產生完全檢查點,下面很多事件將導致增量檢查點,比如:
在聯機熱備份數據文件前,要求該數據文件中被修改的塊從DB_Buffer 寫入數據文件中。所以,發出這樣的命令:
ALTER TABLESPACE tablespace_name BIGEN BACKUP & end backup; 也將觸發和該表空間的數據文件有關的局部檢查點;另外, 
ALTER TABLESPACE tablespace_name READ ONLY;
ALTER TABLESPACE tablespace_name OFFLINE NORMAL;
等命令都會觸發增量檢查點。

關於檢查點的一點具體應用討論:
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成功的了,數據不會丟失!

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

這話看起來有道理,但實際上,dbwr在寫的時候又不斷地在產生dirty buffer ,所以說檢查點發生的時候是期望把該時間點之前的所有髒緩衝區寫入數據文件。
所有的buffer,不在LRU list上就在dirty list上, dbwr寫入的時候,一次寫的塊數是有一個批量寫的隱藏參數控制的。
所以說要是 dbwr將 dirty list也好, lru list上的也好,要實現全部寫入,都是一個現實系統中很難存在的現象。dirty 總是在不斷的產生,dbwr總是在不斷地寫,增量檢查點發生的時候也並不意味着一定要更新數據文件頭,檢查點開始的時候只表示該次檢查點結束的時候要更新數據文件頭的話數據文件頭具有該時間點的一致性。
關於檢查點等待事件:
有些事件的產生必須等待檢查點的完成,才能開始數據庫的其它操作:
日誌文件切換就是其中一個事件,日誌切換必須等待檢查點完成。
log file switch (checkpoint incomplete) 這個等待事件本身也說明,日誌切換時產生的檢查點是需要等待的,這個日誌文件所對應髒塊全部寫完後,檢查點進程更新控制文件和數據頭,然後這個檢查點才能算完成。
也就是說日誌切換必須等待檢查點完成,而檢查點在等待DBWn完成。
這種等待DBWn完成的檢查點,最後一步寫入控制文件和數據文件頭的SCN,肯定是DBWn完成的最後一塊的SCN。
檢查點爲什麼要等待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狀態,不會進行日誌切換,當然也不會發生日誌文件被覆蓋的問題了。
如果沒有設置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太小。

檢查點發生時,出現日誌切換,但是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沒有提交成功。

alter systen switch logfile會觸發完全檢查點;但是爲什麼,日誌切換以後檢查點只能記錄到上一次歸檔日誌產生的時間呢?而不是現在歸檔日誌產生的時間呢?
因爲這時的checkpoint enqueue隊列中,也就是髒塊隊列中髒塊還不夠多,還不足以觸發DBWn寫髒塊。所以,內存裏需要寫入的髒塊所對應的redo還存在於上一個redo log裏,這時你去看該redo log的status爲active。
下面操作日誌中出現當前redo log的status爲current,而上一個redo log的status爲active就說明了這一切。上一個redo log的status爲active正是說明在上一個redo log中還存在未寫入datafile的block所對應的redo。 
SQL> create table gaojf3 as select * from all_objects;
Table created
SQL> insert into gaojf3 select * from gaojf3;
29630 rows inserted
SQL> /
59260 rows inserted
SQL> commit;
Commit complete
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 1 14 8796117861680 08/02/2006 02:29:36 0 13 cicro 08/02/2006 02:33:50
SQL> alter system switch logfile;
System altered
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 2 15 8796117861680 08/02/2006 02:29:36 0 14 cicro 08/02/2006 02:33:50
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 2 15 8796117861680 08/02/2006 02:29:36 0 14 cicro 08/02/2006 02:33:50
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119128114 08/08/2006 00:35:51 1 15 2 16 0200000000000000 0 0 3 1 3 3 16 8796117861680 08/02/2006 02:29:36 0 15 cicro 08/02/2006 02:33:50
從上面試驗中可以看到,完全檢查點正在執行,還沒有執行完畢。因此,切換日誌前後察看x$kccrt,看到的RTCKP_SCN, RTCKP_TIM沒有發生變化。等檢查點執行完畢後(也就是檢查點觸發的dbwr執行完寫操作後),rtckp_scn, rtckp_tim才發生變化。


轉載地址:http://airlgc.blog.51cto.com/161810/26175

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