- 總覽
- 快取策略(Buffer Pool Policies)
- Shadow Paging(No-Steal + Force)
- SQLite Rollback Mode(Steal + Force)
- 總結
- WAL(Write-Head Log)
- 基本思想
- 日誌格式 (Log Schemes)
- 檢查點(Check Point)
- ARIES演算法
- 日誌序列號
- 事務提交流程
- 模糊檢查點(Fuzzy CheckPointing)
- ARIES恢復演算法
總覽
該筆記包含了原課程中關於資料庫恢復的兩節課的內容:
- 資料庫日誌(Database Logging)
- 資料庫恢復(Database Recovery)
資料庫的事務併發控制保障了資料庫在正常執行時的原子性,隔離性和一致性,但是當資料庫在執行事務過程中當機了,導致事務無法正常執行時,該怎麼辦呢?
此時就需要資料庫的恢復機制,來保障異常時,事務的原子性和持久化,而恢復機制的核心思想就是日誌(Logging)。
日誌包括Redo日誌和Undo日誌,分別用來重做資料庫當機前已經提交的日誌,和撤銷未提交的日誌。
恢復機制分為兩個部分:
- 事務執行過程中,如何記錄日誌,確保可以從當機中恢復。
- 當機後,怎麼利用日誌恢復到滿足一致性的狀態,主要採用ARIES演算法。
快取策略(Buffer Pool Policies)
會有資料庫恢復問題,根本原因是為了利用記憶體更新快的特性,資料庫的緩衝區和磁碟資料沒有立刻同步,導致資料不一致。
因此,在介紹資料庫日誌之前,有必要先了解不同的快取策略,會給資料庫恢復問題早餐哪些影響。
- Steal和No-Steal:是否刷髒
- Force和No-Force:事務結束後是否先寫回磁碟再提交成功
Shadow Paging(No-Steal + Force)
不需要恢復策略。
- Master Pointer:指向當前使用的緩衝區
- 開啟時:複製一個緩衝區,緩衝區指向後設資料
- 更新資料時:磁碟上覆制後設資料,然後對應緩衝區指向新資料
- 提交時:將Master Pointer指向新緩衝區
Redo:不需要,因為Force保證只要提交成功,就已經刷盤。
Undo:不需要,No-Steal保證沒有提交的事務不會寫入磁碟,所以把記憶體中的無用緩衝區清理掉即可。
SQLite Rollback Mode(Steal + Force)
在修改資料之前,要先把原資料寫入磁碟中(SQLite 稱為 Journal File)。
- 開啟時:建立空Journal File
- 更新資料時:先把後設資料寫入Journal File,再更新緩衝區資料
- 提交時:刪除Journal File,資料落盤
Redo:不需要。
Undo:檢查是否有Journal File,有則重新寫入磁碟即可。
總結
Steal需要做Undo,No-Force需要做Redo。
No-Steal+Force不需要額外恢復措施,但是效能弱。
Steal+No-Force需要Redo+Undo恢復手段,但是效能高。
大多數資料庫都是 Steal+No-Force。
WAL(Write-Head Log)
基本思想
更新資料的時候同步新增資料修改日誌,事務返回成功前保證日誌已經落盤。
日誌結構:
<BEGIN>
:事務開始<LSN, preLSN, TxnId, Type, ObjectId, Before Value, End Value, UndoNextLSN>
- TxnId和ObjectId記錄事務和物件資訊
- Before Value用於Undo,After Value用於Redo。
- LSN見後文描述
<Commit>
:事務提交
如果使用Append-Only型MVCC可以不需要Before Value。
怎麼區分要做Redo還是Undo:事務是否提交。未提交做Undo,提交了做Redo。
從哪裡開始做Redo和Undo:檢查點Check Point。儲存點之前到日誌都已經刷盤,恢復時只需要對儲存點之後到日誌做Redo和Undo。
Group Commit最佳化:日誌緩衝區滿了或者到一定時限(e.g. 5ms),將日誌緩衝區落盤,而不是每次事務提交都落盤,以此減少IO次數。
日誌格式 (Log Schemes)
形式 | 優點 | 缺點 | |
---|---|---|---|
物理日誌(Physical Log) | 位元組變動記錄日誌 | 恢復快 | 日誌大 |
邏輯日誌(Logical Log) | 一般是SQL語句 | 日誌小 | 每次執行結果不一定一致(如時間和隨機數函式,併發訪問性問題) |
物理邏輯日誌(Phylogical Log) | PageId + Slot Number "Physical-to-a-page, logical-within-a-page" |
- | - |
Phylogical Log是一種折中,現在大多數資料庫都採用這種形式。
檢查點(Check Point)
減少資料恢復時的資料寫回量,將全量恢復變成增量恢復,加快恢復速度。
步驟如下:
- 停滯所有查詢
- 將WAL記錄刷盤
- 將髒頁刷盤
- 將
<CheckPoint>
寫入WAL並刷盤 - 恢復查詢
將CheckPoint作為恢復時日誌分析的起點:CheckPoint後提交的事務做Redo,未提交的做Undo。
ARIES演算法
基本思想:WAL;Undo時記錄撤銷日誌。
日誌序列號
日誌序列號(Log Sequence Number),作為日誌Id標識日誌。
名稱 | 位置 | 定義 |
---|---|---|
flushedLSN | 記憶體 | 上次刷盤時的LSN |
pageLSN | 快取頁 | 該頁上最新更新的LSN |
MasterRecord | 磁碟 | 檢查點的LSN |
recLSN | 髒頁表 | 上次刷盤後的第一個LSN (第一個未刷盤的LSN) |
lastLSN | 活動事務表 | 該事務的最新LSN |
流程:
-
事務更新一個頁時,更新該頁的pageLSN
-
日誌刷盤時,更新flushedLSN
-
快取頁刷盤時判斷:pageLSN <= flushedLSN允許資料落盤,否則不允許,因為日誌還沒落盤。
事務提交流程
新增下面兩種日誌型別:
TXN-END日誌
:表示事務生命期結束,後續日誌不會再出現該事務。
新增TXN-END
前必須保證當前事務的髒頁都刷入磁碟。
CLR日誌
:事務Abort和Crash之後,未提交事務需要進行回滾,CLR日誌(Compensation Log Record)記錄回滾這一行為。
正常提交:走上文提到的流程。
Abort提交:
- 將
ABORT
記錄寫進日誌 - 利用日誌中的preLSN不斷回溯進行undo,對於每個更新記錄
- 記錄CLR Record
- 恢復資料
- 將
TXN-END
寫進日誌
正常提交時,TXN-END
接在COMMIT
之後;Abort時,ABORT
和TXN-END
之間是CLR Records。
模糊檢查點(Fuzzy CheckPointing)
原有檢查點的問題:需要將所有髒頁刷盤;停止所有事務,避免刷盤過程中產生新的髒頁;不確定當前有哪些活動事務,導致需要重放所有日誌確定哪些日誌沒有提交。
模糊檢查點:將檢查點由一個時間點變成時間段,並且記錄活動事務(ATT)和髒頁(DPT)。
CHECKPOINT-BEGIN
:檢查點開始CHECKPOINT-END
:記錄ATT+DPT
ARIES恢復演算法
總過程
- 分析階段:構建DPT和ATT
- Redo階段:從DPT找到最小的recLSN(從此處開始未刷盤),開始Redo
- Undo階段:從ATT找到每個活動事務的lastLSN(該事務的最新LSN),用preLSN逆推所有修改,開始Undo
分析階段:從CHCKPOINT-BEGIN
開始
- 每遇到一個事務,新增到ATT,狀態為U
- 每遇到一個髒頁,新增到DPT
- 每遇到一個
COMMIT
,修改事務狀態為C;TXN-END
,將事務移除ATT - 過程中,維護DPT表的lastLSN和ATT表的recLSN
Redo階段:
- 找到DPT中最小的reclSN
- 對於每個update log record和CLR,進行重做,除非:
- 不在DPT內
- 在DPT內,但是LSN < 最小的recLSN
- LSN <= pageLSN
- 對於所有狀態為C的事務,新增
TXN-END
,然後從ATT中刪除。
Undo階段:對於每個狀態為U的事務,用recLSN逆推所有更新,新增CLR
例子如下,沒有體現Redo過程:
Crash前:
兩次Crash後,\(T_2\)和\(T_3\)已經提交TXN-END
,從ATT表刪除。