hello大家好,好久不見!今天我們繼續學習《教妹學數據庫系統》。教妹學數據庫,沒見過這麼酷炫的標題吧?“語不驚人死不休”,沒錯,標題就是這麼酷炫。
我的妹妹小埋18歲,校園中女神一般的存在,成績優異體育萬能,個性溫柔正直善良。然而,只有我知道,衆人眼中光芒萬丈的小埋,在過去是一個披着倉鼠斗篷,滿地打滾,除了吃就是睡和玩的超級宅女。而這一切的轉變,是從那一天晚上開始的。
從此之後,小埋經常讓我幫她輔導功課。今天她想了解數據庫系統中的故障恢復。本篇教程通過我與小埋的對話的方式來談一談故障恢復。
故障恢復(failure recovery)
故障發生後,DBMS將數據庫恢復到最新的一致性狀態
故障(Failure)的類型
事務故障
邏輯錯誤(LogicalErrors)
- 事務由於內部錯誤(internalerror)而無法完成,如違反完整性約束(integrityconstraint)
內部狀態錯誤(InternalStateErrors)
- DBMS由於內部狀態錯誤(如死鎖)而必須中止活躍事務(activetxn)
系統故障(SystemFailures)
軟件故障(SoftwareFailures)
- DBMS實現的bug所導致的故障
硬件故障(HardwareFailures)
-
運行DBMS的計算機發生崩潰(crash),如斷電
-
假設系統崩潰不會損壞非易失存儲器中的數據
存儲介質故障(StorageMediaFailures)
非易失存儲器發生故障,損壞了存儲的數據
假設數據損壞可以被檢測,如使用校驗碼(checksum)
任何DBMS都無法從這種故障中恢復,必須從備份(archive)中還原(restore)
Buffer Pool Policies
DBMS在故障恢復時會做2種操作
撤銷(Undo)
- Undo未完成事務(incomplete txn)對數據庫的修改
重做(Redo)
- Redo已提交事務(committed txn)對數據庫的修改
DBMS如何支持undo和redo取決於DBMS如何管理緩衝池(bufferpool)
STEAL策略
DBMS是否允許將未提交事務所做的修改寫到磁盤並覆蓋現有數據?
- STEAL:允許
- NO-STEAL:不允許
FORCE策略
DBMS是否要求事務在提交前必須將其所做的修改全部寫回磁盤?
- FORCE:要求
- NO-FORCE:不要求
緩衝池策略(Buffer Pool Policies)
例如:NO-STEAL+FORCE
shadow paging
NO-STEAL ⇒ 未提交事務不可能將其修改寫回磁盤 ⇒ 無需undo
FORCE ⇒ 已提交事務已將其修改全部寫回磁盤 ⇒ 無需redo
優點: 實現簡單
缺點: 緩衝池得能存得下所有未提交事務所做的修改
Write-Ahead Logging(WAL)
預寫式日誌(WAL)
DBMS在數據文件(datafile)之外維護一個日誌文件(logfile),用於記錄事務對數據庫的修改。
-
假定日誌文件存儲在穩定存儲器(stable stroage)中
-
日誌記錄(log record)包含undo或redo時所需的信息
DBMS在將修改過的的對象寫到磁盤之前,必須先將修改此對象的日誌記錄刷寫到磁盤。
WAL協議(WAL Protocol)
當事務Ti啓動時,向日志中寫入記錄<tid,BEGIN>
- tid:Ti的ID(txn ID)
當Ti提交時,向日志中寫入記錄<tid,COMMIT>
- 在DBMS嚮應用程序返回確認消息之前,必須保證Ti的所有日誌記錄都已刷寫到磁盤
當Ti修改對象A時,向日志中寫入記錄<tid,oid,before,after>
- oid:A的ID(object ID)
- before:A修改前的值(undo時用)
- after:A修改後的值(redo時用)
基於WAL的故障恢復
第1部分:事務正常執行時的行爲
-
記錄日誌
-
按照緩衝池策略將修改過的對象寫到磁盤
第2部分: 故障恢復時的行爲
- 根據日誌和緩衝池策略,對事務進行undo或redo
根據日誌的事務分類
根據日誌將事務分爲3類
已提交事務(Committed Txn)
- 既有<T,BEGIN>,又有<T,COMMIT>
不完整事務(Incomplete Txn)
- 只有<T,BEGIN>,而沒有<T,COMMIT>
已中止事務(AbortedTxn)
-
既有<T,BEGIN>,又有<T,ABORT>
-
在事務正常執行和故障恢復過程中,如果T所做的修改已全部撤銷,則將日誌記錄<T,ABORT>寫到日誌
-
已中止事務相當於從未執行過,故不需要undo,更不需要redo
WAL協議的分類
根據緩衝池策略的不同,可以實現3類WAL協議
-
UndoLogging: WAL+STEAL+FORCE
-
RedoLogging: WAL+NO-STEAL+NO-FORCE
-
Redo+UndoLogging: WAL+STEAL+NO-FORCE
WAL Undo Logging
基於Undo Logging的事務正常執行時的行爲
基於Undo Logging的故障恢復
已提交事務(Committed Txn): 不需要恢復
- FORCE=⇒已提交事務所做的修改已全部寫入磁盤
不完整事務(Incomplete Txn): 全部undo
- STEAL=⇒不完整事務所做的一部分修改可能已經寫入磁盤
從後(最後一條記錄)向前(第一條記錄)掃描日誌。根據每條日誌記錄的類型執行相應的動作。
WAL Redo Logging
事務正常執行時的行爲
基於Redo Logging的事務正常執行時的行爲
基於Redo Logging的故障恢復
已提交事務(CommittedTxn): 全部redo
- NO-FORCE ⇒ 已提交事務所做的修改可能尚未全部寫入磁盤
不完整事務(IncompleteTxn): 不需要恢復
- NO-STEAL ⇒ 不完整事務所做的任何修改都未寫入磁盤
WAL Redo+Undo Logging
已提交事務(CommittedTxn): 全部redo
- NO-FORCE ⇒ 已提交事務所做的修改可能尚未全部寫入磁盤
不完整事務(IncompleteTxn): 全部undo
- STEAL ⇒ 不完整事務所做的一部分修改可能已經寫入磁盤
基於Redo+UndoLogging的故障恢復方法
Redo階段: redo已提交事務
- 與基於RedoLogging的故障恢復方法相同
Undo階段: undo不完整事務
- 與基於UndoLogging的故障恢復方法相同
先redo,再undo
緩衝池策略的比較
組提交(GroupCommit)
每條日誌記錄單獨刷寫(flush)到磁盤的I/O開銷太大。
在內存中設置日誌緩衝區(logbuffer),將日誌記錄寫到日誌緩衝區,然後成批刷寫到日誌文件。
- 日誌緩衝區滿時刷寫
- 定時刷寫
Checkpoints
- WAL的問題
- 日誌永遠在變大
- 故障恢復時需要掃描日誌,恢復時間越來越長
- 檢查點(Checkpoints)
DBMS定期設置檢查點(checkpoint)
- 將日誌刷寫到磁盤
- 根據緩衝池策略,將髒頁(dirtypage)寫到磁盤
- 故障恢復時只需掃描到最新的檢查點
- 模糊檢查點(FuzzyCheckpoints)
檢查點開始: 向日志中寫入<BEGINCHECKPOINT(T1,T2,…,Tn)>
- T1,T2,…,Tn是檢查點開始時的活躍事務(active txn)
- 活躍事務是尚未提交或中止的事務
檢查點中間: 根據緩衝池策略,將髒頁(dirtypage)寫到磁盤
- 如果採用STEAL,則將全部髒頁寫到磁盤
- 否則,只將已提交事務所做的修改寫到磁盤
檢查點結束: 向日志中寫入,並將日誌刷寫到磁盤
- 如果採用NO-FORCE,則寫完全部髒頁後即可結束檢查點
- 否則,在T1,T2,…,Tn全部提交後,才能結束檢查點
Redo階段
不完整的檢查點只有開始沒有結束,在檢查點的過程中遇到系統故障,是無用的。
日誌中最新的完整檢查點
<BEGINCHECKPOINT(T1,T2,...,Tn)>
...
< ENDCHECKPOINT >
需要redo的最早的事務一定屬於{T1,T2,…,Tn}。
從日誌記錄<BEGINCHECKPOINT(T1,T2,…,Tn) > 開始向後掃描日誌不需要從最早的<Ti,BEGIN>開始掃描。
<T,COMMIT>,在< ENDCHECKPOINT >在檢查點結束前寫入磁盤了。
Undo階段
日誌中最新的完整檢查點
<BEGINCHECKPOINT(T1,T2,...,Tn)>
...
<ENDCHECKPOINT>
需要undo的最早的事務一定屬於{T1,T2,…,Tn}。
掃描到T1,T2,…,Tn中最早的事務Ti的日誌記錄<Ti,BEGIN>爲止。
總結
咱們玩歸玩,鬧歸鬧,別拿學習開玩笑。
本篇介紹了故障恢復,緩衝池策略、WAL協議和檢查點。最常用的緩衝池策略是STEAL+NOFORCE,學習時要加深理解和記憶。