由於Oracle中LGWR和DBWR工作的不一致,Oracle引入了檢查點的概念,用於同步數據庫,保證數據庫的一致性。在Oracle里面,檢查點分為兩種:完全檢查點和增量檢查點。下面我們分別介紹這兩種檢查點的作用:
1、完全檢查點
在Oracle8i之前,數據庫的發生的檢查點都是完全檢查點。完全檢查點會將數據緩沖區里面所有的臟數據塊寫入相應的數據文件中,同時將最新的checkpoint scn更新到所有的數據文件頭部及控制文件。保證數據庫的處於一致的狀態。需要注意的是,完 全檢查點產生的時候,CKPT並不是把當前完全檢查點發生那一時刻的SCN更新到控制文件和數據文件頭,而是將這個觸發檢查點時刻DBWn當前剛寫完 dirty buffer對應的SCN更新到控制文件和數據文件頭,也就是說,更新控制文件和數據文件頭的SCN是滯后於完全檢查點的發生那一時刻的SCN的,這個從恢復的原理也很容易理解,因為檢查點發生的時候要寫入dirty buffer還沒有寫入,自然不能立即更新成當前的SCN了。需 要注意的是, 在oracle8之前,由於沒有chekpoint queue,也沒有增量檢查點的概念,發生完全檢查點時,DBWn會以一種無序的方式將所有的 dirty buffer寫出到數據文件,這個時候Oracle會凍結所有DML操作等候所有dirty buffer被寫出,巨大的IO往往會影響到數據庫的性 能。后來隨着Oracle數據庫的發展和buffer cache的不斷增大,oracle 意識到這個單一的Full checkpoint機制已經不能滿足需要,所以在Oracle 8i后提出增量檢查點的概念,建立了checkpoint queue ,讓dirty buffer header根據首次變化時候的順序(LRBA)排列在queue里面。 這樣DBWn只要順着queue的順序寫,而其他進程不必等候dbwr的寫完成就可以繼續。 因此增量檢查點的概念就由此產生了。
完全檢查點在8i之后只有在下列兩種情況下才會發生:
DBA手工執行alter system checkpoint的命令;
數據庫正常shutdown (immediate,transcational,normal)。
2、增量檢查點
說白了,就是
CKPT每3秒一次的檢查DBWn寫進度並在控制文件中記錄檢查點位置(checkpoint position)和更新heartbeat信息
以及
CKPT定期觸發DBWn去寫checkpoint queue中的臟數據這兩項操作合一起被稱為增量檢查點。 -->可能這塊描述的過於籠統,大家繼續往下看:-)
我們都知道被修改過的數據塊,在oracle中都被統稱為臟數據塊(dirty buffer)。所有的臟塊被一個鏈表串起來,稱做檢查點隊列(checkpoint queue)。在buffer cache中,每一個塊都有一個buffer header簡稱BH, 在BH中有一個ckptq項, 此項目中記錄了指向檢查點隊列上一個塊和下一個塊的指針。 如果某一個塊不在檢查點隊列中,他的ckptq項為空.通過ckptq項oracle將所有的臟塊串成了一個雙向鏈表。這個雙向鏈表就是檢查點隊列了。
Oracle 從8i開始引入了檢查點隊列(checkpoint queue)的概念,用於記錄數據庫里面當前所有的dirty buffer的信息,這些dirty buffer的信息按被修改的時間先后存放在checkpoint queue里面(當塊首次被更改時,塊會立即被加進檢查點隊列),所涉及的條目主要包含RBA (Redo Block Address,重做日志里面用於標識事務期間數據塊在重做日志里面發生更改的編號)和數據塊的數據文件號和塊號。
不 論數據塊(buffer)更改幾次,它在checkpoint queue里面的位置始終保持不變,checkpoint queue也只會記錄它最早的RBA(這個最早的RBA其實就是Low RBA,也就是數據塊第一次被修改時所對應的RBA),從而保證最早更改的數據塊能夠盡快從內存寫入數據文件。DBWR每到一定的時機,就會被觸發 (DBWn並不是只有當檢查點發生的時候才寫,它大約有10幾種條件觸發寫操作),沿着檢查點隊列的順序刷新臟塊,同時CKPT進程,會監控着檢查點隊列 的長度,當檢查點隊列的長度達到一定限制時(具體有幾個參數來確定checkpoing queue的長度,下面會提到比如log_checkpoint_timeout,fast_start_mttr_target等),CKPT會通知 DBWR寫臟塊。CKPT會根據幾個參數的設置和I/O的速度以及繁忙程度,計算出來一個Target rba(目標rba),DBWn會沿着檢查點隊列,按照dirty buffer的Low RBA順序將所有Target rba之前對應的臟塊從內存寫入數據磁盤文件。當CKPT通知完DBWn Target rba后,CKPT的任務就結束了。他並不會等待DBWn寫完所有的Target rba之前的臟塊。因此這里CKPT只是起到了一個通知DBWn進程寫入的作用。
當完全檢查點發 生的時候,Oracle一方面通知DBWn進行下一批寫操作,另一方面是將這個觸發檢查點時刻DBWn當前剛寫完dirty buffer對應的SCN寫入數據文件頭和控制文件,這個SCN就是checkpoint scn。但Oracle考慮到檢查點SCN的間隔還是太大了,因為檢查點的觸發條件有限,周期可能比較長,有些情況下比如檢查點需要5分鍾左右才觸發,那 這個時候系統crash再重新啟動就意味着很可能系統需要5分鍾左右才能啟動。於是Oracle采用了一個heartbeat的概念,以3秒的頻率將 DBWn寫的進度反應到控制文件中,這樣系統crash重新啟動的時候將從更近的一個時間點開始恢復。Oracle這么做的目的就是要縮短崩潰恢復時間! 因此CKPT另外一個任務就是每3秒,檢測一次DBWn的寫進度。DBWn 是沿着檢查點隊列寫臟塊,由於這里有一個順序的關系,所以DBWn的寫的進度就是可衡量的,寫到哪個buffer的時候該buffer的首次變化時候的 scn(對應了LRba)就是當前所有數據文件block的上面最新scn,但是由於無法適時的將DBWn的進度記錄下來,所以Oracle選擇了一些策 略。 其中就包括CKPT進程的檢查點位置更新和心跳,所以說CKPT每3秒鍾查看一下DBWn沿檢查點隊列寫到了哪里,並且將這個位置設置為檢查點位置 (checkpont position)。也就是說檢查點位置之前的塊,都是已被DBWn刷新到磁盤上的塊。因此我們可以理解為,CKPT進程每3秒會根據DBWn寫的進度設置並記錄一個檢查點位置,也就是說這個檢查點位置就是由DBWn的在往Target RBA寫過程中的進度決定的(如果沒有dirty buffer產生,那么就不會更新檢查點位置信息)。因 此CKPT每3秒會將檢查點位置對應的數據塊的rba (low cache rba-表示Instance Recovery時開始恢復的日志條目)更新和記錄到控制文件的CHECKPOINT PROGRESS RECORDS區域,當然同時被記錄進控制文件的還有heartbeat等其他信息。DBWn將檢查點隊列里面的dirty buffer寫入到數據文件后,檢查點的位置也要相應地往后移。
檢 查點位置(checkpoint position)實際上就可以直接理解為是一個rba,他指向着重做日志文件中的某條重做記錄。在此檢查點位置前的重做記錄,其對應的buffer cache中的dirty buffer已經被寫進了數據文件,在此位置后的重做記錄,所對應數據臟塊有可能還在內存中。如果發生了實例崩潰,只需要在日志文件中找到檢查點位置 (low cache rba),從此處開始應用所有的重做日志文件,就完成了前滾操作。實例崩潰后,再次啟動數據庫,oracle會到控制文件中讀取low cache rba,這就是檢查點位置。從此處開始應用重做日志,應用到on disk rba的位置。
on disk rba是磁盤中重做日志文件的最后一條重做記錄的rba。
如 果某條重做記錄的rba高於on disk rba,那說明此重做記錄還沒有被寫進日志文件中,崩潰發生時,他是不可能被恢復的。on disk rba是oracle前滾操作的終點。比這個更高的rba,都應該還駐留在log buffer中。還沒有被LGWR寫入日志文件。所以是不能被用於恢復的。
在DBWn寫dirty buffer這個檢查點過程中,Oracle也可以繼續產生dirty buffer,DBWn也不是一次要把所有dirty buffer全部寫到磁盤(不同於完全檢查點的地方),這樣就提高了檢查點的效率,使得數據庫要做恢復的時候從這個最新位置開始做恢復,而不是從數據文件 中的checkpoint scn(上一個完全檢查點位置) 開始做恢復,這樣將縮短恢復時間。
Oracle
11g
的 Concept里面提到:An incremental checkpoint is a type of thread checkpoint partly intended to avoid writing large numbers of blocks at online redo log switches. DBWn checks at least every three seconds to determine whether it has work to do. When DBWn writes dirty buffers, it advances the checkpoint position, causing CKPT to write the checkpoint position to the control file, but not to the
data
file headers.
因此我們需要注意的是:
增量檢查點並不會去更新數據文件頭,以及控制文件中數據庫SCN以及數據文件條目的SCN信息,而只是每3秒由CKPT進程去更新控制文件中的low cache rba信息,也就是檢查點的位置。
檢查點位置發生變更后, Oracle主要通過4個參數和1個機制來控制檢查點位置和最后的重做日志條目之間的距離(檢查點隊列的長度)。
fast_start_io_target (Oracle 9i以后已經廢棄)
該 參數用於表示數據庫發生Instance Recovery的時候需要產生的IO總數,它通過v$filestat的AVGIOTIM來估算的。比如我們一個數據庫在發生Instance Crash后需要在10分鍾內恢復完畢,假定OS的IO每秒為500個,那么這個數據庫發生Instance Recovery的時候大概將產生500*10*60=30,000次IO,也就是我們將可以把fast_start_io_target設置為 30000。
fast_start_mttr_target
我 們從上面可以看到fast_start_io_target來估算檢查點位置比較麻煩。Oracle為了簡化這個概念,從9i開始引入了 fast_start_mttr_target這么一個參數,用於表示數據庫發生Instance Recovery的時間,以秒為單位。這個參數我們從字面上也比較好理解,其中的mttr是mean time to recovery的簡寫,如上例中的情況我們可以將fast_start_mttr_target設置為600。注意當設置了 fast_start_mttr_target后, fast_start_io_target這個參數將不再生效,從9i后 fast_start_io_target這個參數被Oracle廢除了。
log_checkpoint_timeout
該參數用於表示檢查點位置和重做日志文件末尾之間的時間間隔,以秒為單位,默認情況下是1800秒。
相 比fast_start_mttr_target,它也是時間,但它的時間值表示完成恢復操作所需要的時間,即從最后的檢查點位置開始,應用所有日志直到 日志末尾所需要的時間。而本參數log_checkpoint_timeout表示從最后的檢查點位置開始,到日志末尾經過的時間。
log_checkpoint_interval
該參數是表示檢查點位置和重做日志末尾的重做日志塊的數量,以OS塊表示。
90% OF SMALLEST REDO LOG
除了以上4個初始化參數外,Oracle內部事實上還將重做日志文件末尾前面90%的位置設為檢查點位置。在每個重做日志中,這么幾個參數指定的位置可能不盡相同,Oracle將離日志文件末尾最近的那個位置確認為檢查點位置。
在Oracle 9i后,對檢查點頻率,建議只設置fast_start_mttr_target。根據需要,也可以通過設置 log_checkpoint_timeout,設置一個臟塊保持臟狀態的最大時間,而其他兩個參數 fast_start_io_target,log_checkpoint_interval建議不再使用。