mysql的checkpoint


上一章的結尾我們留下了一個問題,就是在上一章所介紹的模型中,恢復管理器必須要通過全篇掃描整個undolog進行日志恢復,這樣做顯然是沒有太大必要的,因為系統中斷肯定是在最后幾個事務受到影響,前面的事務應該已經完成commit或者rollback了,不會出現abort的情況,那我們如何知道哪些事務受到了影響呢,如果我們知道了哪一些事務受到了影響,那我們就可以不用全篇進行掃描,而僅僅掃描很小的一部分就可以了。下面就介紹下,數據庫如何知道哪些事務受到了影響,數據庫為了得到這個目的,引入了檢查點(checkpoint)這個概念。

checkpoint 檢查點

checkpoint,即檢查點。在undolog中寫入檢查點,表示在checkpoint前的事務都已經完成commit或者rollback了,也就是檢查點前面的事務已經不存在數據一致性的問題了。那這個checkpoint如何去實現呢。其實實現的機制很簡單,就是周期性的往undolog里面寫入。當然這個寫入肯定不是隨隨便便的往里寫,在往里寫的時候,肯定要檢查前面的事務是否完成。

這個時候就會帶來一個問題,因為數據庫是一直在運行的,也就是事務是在不斷啟動的,同時可能有n個事務已經處於開始狀態。而在檢查點往里寫的時候,可能又有新的事務啟動了,如果讓檢查點一直等到沒有新的事務啟動而且前面所有的事務又都提交過了估計很難,那基本檢查點就不用往里寫了。所以,在這種情況下,只能是在檢查點往里寫的時候,停止接受新事務,等待已啟動的事務提交完畢,然后檢查點寫入完畢。然后繼續接受新事務。類似於這樣: 例如,現在有T1 T2兩個事務,則undolog中寫入:

undolog
start T1
<T1,A,x>
start T2
<T2,B,y>

這時到了檢查點的周期,要往里寫入檢查點了,就得等到T1,T2全部提交完畢,然后寫入檢查點chkpoint。也就是如果現在有一個T3要開啟,是無法開啟的。系統處於夯住狀態。寫入完后,開啟T3,日志記錄如下:

undolog
start T1
<T1,A,x>
start T2
<T2,B,y>
end T1
end T2
chkpoint
start T3

這時候,如果系統掛掉了,故障恢復管理器會從undolog的尾部向前進行掃描,掃描到checkpoint后,就不會往前掃描了,因為前面的事務都已經提交過了,不存在數據一致性問題。所以只需要從checkpoint開始重做即可。

這樣固然是好,省掉了需要undolog從頭開始掃描的麻煩,但是這樣做的缺點也很明顯,那就是在寫入checkpoint的過程中,系統是出於夯住狀態的,所有的寫入都要暫停。那能否有一種更好的方法既可以寫入checkpoint又不需要系統暫停呢,必須的,當然有,這就是下面要講的非靜態檢查點。

非靜態檢查點

非靜態檢查點是相對於靜態檢查點而來的,上文中所提到的就屬於靜態檢查點,因為在檢查點寫入的同時,系統是不能寫入的。而非靜態檢查點的引入,就是要解決這個問題。

非靜態檢查點的策略是在寫入chkpoint的同時,會記錄下當前活躍的事務。比如,當前狀態下,T1和T2都是活躍狀態,那么undolog中會被寫入start checkpoint(T1,T2),這時整體系統仍然是正常寫入的,也就是說在這條log寫入后,仍然可以繼續開啟其他事務。當T1,T2完成后,會寫入end checkpoint的記錄。例如如下記錄:

undolog
start T1
<T1,A,x>
start T2
<T2,B,y>
start checkpoint(T1,T2)
start T3
end T1
end T2
end chkpoint
start checkpoint(T3)
end T3
end chkpoint

上面這個日志記錄就是,在T1,T2開始后,undolog中寫入了start checkpoint(T1,T2)的檢查點,而這時仍然是可以接受其他事務的開始的,這時有了T3事務的開啟。

通過這種機制,可以有效避免在檢查點寫入時需要停掉服務的弊端,但現在問題又來了,這樣寫檢查點固然是好,但恢復管理器如何通過這樣的undolog去進行數據恢復操作呢?因為,如果檢查點是靜止的,那找到checkpoint后,就不必再往前找了,而現在不一樣了,因為找到end checkpoint后,前面仍可能有未完成的事務,那這時數據恢復是如何恢復的呢?

在這種情況下,數據庫宕機后,恢復管理器仍然會從尾往前進行掃描undolog,如果遇到了“end chkpoint”,這時並不代表checkpoint前所有的事務都已經提交了,但我們可以知道,所有未提交的事務都是在上一個start checkpoint之后,所以會繼續往前找,一直找到start checkpoint,找到start checkpoint后,比如是start checkpoint(T1,T2),因為先前已經找到了end chkpoint,所以T1,T2這兩個事務已經可以保證數據一致性了,需要重做的就是在start checpoint(T1,T2)到end chkpoint間的這一些非T1,T2事務,這些是需要重做的,所以要把這些進行重做。

還有另外一種情況,就是恢復管理器在掃描時,先遇到了start checkpoint(T1,T2)的日志,在這種情況下,我們首先知道了T1,T2或許是未完成的事務,那這時需要在start checkpoint之后找到是否有某個事務的end語句,如果有,說明這個事務是完成了,如果沒有,就說明沒有完成,那就要從check point再往后尋找,找到這個事務的start,然后從start之后往后重做。說得比較羅嗦,我們上個例子來說明下這種情況。

例如,數據庫宕機后,開始掃描undolog,得到以下片段:

undolog
start T1
<T1,A,15>
start T2
<T2,B,39>
start checkpoint(T1,T2)
start T3
<T3,C,40>
end T1
<T3,C,50>

這時,恢復管理器拿到這個片段后進行掃描,在遇到end chkpoint前遇到了start checkpoint(T1,T2),這說明了,T1,T2是可能未完成事務的,而且在這之前還遇到了T3的start,沒有end T3,也沒有任何T3的檢查點的開始,這說明了T3一定是未完成事務的,所以T3一定是要重做的。先前為什么說T1,T2是可能未完成事務的呢?因為遇到了start checkpoint(T1,T2),沒有遇到end chkpoint,並不代表T1和T2就一定是未完成的,可能有一個已經commit過了,因為兩個都沒有commit,所以才導致了沒有end chkpoint,所以這時找start下面的日志,發現了“end T1”,說明了T1的事務是已經完成了的。那只需要找T2的開啟然后開始重做就可以了,然后就通過start checkpoint(T1,T2)再往上找,找到了start T2,然后開始重做T2,也就是這個日志里,T2和T3是需要重做的,然后重做掉。 (注:剛才先說了做T3,然后有說了重做T2,並不代表真正的順序就是這樣,實際上恢復管理器是先分析出需要重做的事務,然后一塊做掉的。)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM