數據庫恢復子系統的常見技術和方案對比(一)

做者:實驗室小陳/大數據開放實驗室算法

對於事務型數據庫而言,最關鍵的功能是要保證事物ACID屬性,其中原子性和持久性依靠恢復子系統保證。事務在進行中若是發現沒法繼續,就須要用恢復子系統進行回滾;或者出現系統崩潰,也須要依靠恢復子系統把數據庫恢復到崩潰前狀態。在本專欄中,咱們主要介紹Logging Protocols / Recovery Algorithms,它們分別是事務型數據庫恢復子系統中的兩個關鍵部分。數據庫

—Logging Schemes—

恢復子系統中的關鍵是恢復算法,目的是要實現兩個過程。首先是事務執行過程當中爲系統恢復作的準備工做,目前大多數系統一般採用日誌記錄方式,儘管事務執行過程當中同時記錄數據更新日誌會有額外開銷,但若是沒有日誌,一旦系統崩潰則沒法實現系統恢復和未完成事務的回滾。此外,還有Shadow Paging方案,即數據每次修改都經過Copy-on-Write的方式進行。在更新數據時,複製一份原數據的副本並在副本上進行更新,最後經過用副本替換原始數據的方式完成操做。Shadow Paging方案開銷較大,通常用在更新不頻繁的場景下,如文本編輯器等相似場景,所以事務型數據庫系統裏大都採用基於日誌的方案。第二個過程是在出現系統故障或事務回滾的狀況時,如何利用系統記錄的日誌信息並採用合適策略來保證數據庫可以恢復到正確狀態。數據結構

  • Physical Logging & Logical Logging併發

Logging分爲Physical Logging和Logical Logging兩類。Physical Logging指在日誌記錄中記錄對數據項的修改,如數據項A在修改以前的值爲90,修改以後是100,Physical Logging會將數據項A的變化過程記錄下來。在一個數據庫系統中,Physical Logging多是Value Logging,即記錄數據項、數據項ID、修改前/後的屬性值等信息;也多是真正的物理Logging,即記錄磁盤頁面PageID、Offset和長度,以及修改先後的值。app

另一類是Logical Logging,不記錄執行結果,只記錄對數據修改的操做如delete / update等。較於Physical Logging根據修改先後的值進行恢復或重放,Logical Logging在重放時須要從新執行日誌中的操做,在回滾時須要執行日誌中所記錄操做的逆操做,好比插入對應的刪除等。async

  • Physical Logging VS Logical Logging

兩種Logging各有優缺點。Logical Logging記錄的日誌內容較少,好比update操做,Logical Logging只須要記錄一條update語句便可,日誌記錄開銷少。缺點是在併發場景下較難實現,當同時有多個事務產生更新操做時,數據庫內部會將這些操做調度爲串行化序列執行,須要機制來保障每次回放操做的執行順序與調度產生的順序一致。因此,大多數數據庫系統採用Physical Logging來保證數據恢復的一致性,事務管理器(併發控制子系統)所產生的事務操做執行順序會以日誌的方式被記錄下來,恢復子系統根據日誌順序可以保證每個數據項修改的回滾和重放都按照順序嚴格執行。但目前,有一些數據庫系統依舊使用Logical Logging,如內存數據庫引擎VoltDB,這是由於VoltDB引擎設計上沒有併發控制,每一個CPU內核都順序執行全部操做,所以能夠經過Logical Logging按序回放。 編輯器

對於數據庫管理系統而言,要保證故障發生狀況下的數據持久性和正確性,所以恢復子系統不可或缺。在事務執行過程當中,須要撤銷時可以回滾以保障原子性;但同時恢復子系統會帶來性能影響,由於全部日誌記錄只有刷到磁盤上纔算真正落盤,即便事務全部操做所有完成,也必定要等日誌落盤後才能響應客戶端,所以Logging的性能每每成爲整個系統的性能瓶頸高併發

—Recovery System Optimization—

對於日誌或恢復子系統的優化,主要有兩類技術,一類是Group Commit,另外一類是Early Lock Release。性能

  • Group Commit

Group Commit是將並行執行的一組事務日誌一塊兒刷到磁盤,而非分事務每條日誌刷一次。日誌有單獨的日誌緩衝區,全部事務先把日誌寫進日誌緩衝區,經過設置單獨線程定時將日誌緩衝區中的內容刷進磁盤,或當日志緩衝區存儲滿時再刷到磁盤。大數據

操做系統提供了Sync、Fsync、Fdatasync等不一樣寫磁盤的方式,其中Sync把數據刷到操做系統文件緩衝區時就視爲結束,隨後靠操做系統後臺進程把緩衝區的內容刷到磁盤,所以經過Sync方式刷磁盤可能會形成數據丟失。數據庫系統一般採用Fsync進行日誌落盤,當記錄真正寫到磁盤裏面時才返回。Fsync是將文件數據以及文件元數據如修改時間、文件長度等信息一塊兒寫到磁盤;而Fdatasync跟Fsync的區別在於其只刷數據而不刷元數據。

在一些DBMS中,會混用Fsync和Fdatasync:當元數據修改不影響Logging,好比只有文件修改時間變化,這時只用Fdatasync便可;但若是操做修改了文件長度,這時就不能用Fdatasync,由於Fdatasync並不保存元數據修改信息,在恢復時會形成內容部分缺失。因爲不少DBMS在寫日誌時不是以增量方式增長日誌文件內容,而是一次性爲日誌文件分配足夠空間,在以後的寫日誌過程當中日誌文件長度保持不變,因此能夠用Fdatasync將日誌寫到磁盤。能夠看到,Group Commit每次將一組事務使用一個系統調用寫到磁盤,合併不少事務I/O,從而下降整個系統的I/O。

  • Early Lock Release

在基於鎖機制實現併發控制時,若是前序事務的鎖沒有釋放,後面的事務只能處於等待鎖的狀態。圖中黑色部分表示正在進行的事務操做,灰色部分是等待日誌落盤的時間,雖然此時對數據不作修改,但只有等日誌刷到磁盤後才能釋放鎖。Early Lock Release是一種面向此場景提升性能的優化方法,策略是當事務中處理工做的部分作完就釋放鎖,而後再將日誌落盤,縮短下個事務等待鎖的時間,提升併發執行程度。

 

但這種方式一樣存在缺陷,好比第一個事務已經釋放鎖,但在日誌落盤時出現故障須要回滾,但因爲此時鎖已經被下一個事務得到,下一個事務要和上一個事務一塊兒回滾,所以系統須要維護事務間的依賴關係。在現實中,鎖的提早釋放技術在數據庫中被普遍使用。對於索引結構,若是對索引中的某個節點加鎖,會產生較大影響範圍,由於一個索引葉子節點每每涉及一連串的不少數據記錄。若是對葉子節點加鎖,相關記錄都會被鎖住。所以在索引的使用上,一般會採用Early Lock Release而非兩階段封鎖協議,以縮短數據記錄被鎖住的時間。

—ARIES算法—

在基於磁盤的數據庫系統中,恢復子系統大都是基於ARIES(Algorithms for Recovery and Isolation ExploitingSemantics)算法實現。ARIES對於數據緩衝區和日誌緩衝區的管理採用Steal + No Force的管理策略(關於Steal + No Force的介紹在《內存數據庫解析與主流產品對比(一)》中有詳細提到)。在ARIES中,每條日誌會有一個順序號LSN(Log Sequence Number),以下圖中LSN 10號的日誌是事務T1寫Page 5的更新操做;20號LSN是事務T2寫Page 3的更新操做。須要注意的是,日誌中會保留有事務end記錄,標識事務已commit並返回客戶端,表示該事務全部操做已經完成。若是日誌中只有commit而沒有end,那可能意味着事務已經完成,但客戶端可能沒有收到響應。

  • ARIES三階段恢復

ARIES的恢復算法分三個階段:Analysis、Redo、Undo,每階段具體細節後面會詳細介紹

  1. Analysis:在出現crash重啓後,系統首先會從磁盤上讀出日誌文件,分析日誌文件內容,判斷哪些事務在系統crash時處於Active狀態,以及哪些Page在出現故障時被修改過。

  2. Redo:系統在redo階段根據日誌重現故障現場,包括將內存中的Dirty Page恢復到crash時的狀態,至關於重放日誌歷史記錄(Repeating History),並將每條日誌記錄都執行一遍,包括沒有commit的事務日誌。

  3. Undo:Undo階段系統開始撤銷沒有完成的事務。上圖是日誌記錄的簡單示例,系統在LSN 60後crash,其中日誌中有事務T2 end的標記,因此T2已經提交,而事務T1和T3都還沒有完成,事務T1和T3對於P一、P3和P5的修改若是已落盤,就須要從磁盤上撤銷。

  • 日誌記錄的數據結構

對於ARIES恢復子系統,恢復過程須要基於Logging所存儲的信息進行。ARIES中日誌由多條日誌記錄組成,一條日誌記錄裏包含修改數據項的事務ID、Page ID + Offset、長度、修改先後的數值以及額外的控制信息。

ARIES的日誌類型包括Update、Commit、Abort、End以及補償日誌記錄CLR(Compensation Log Record )。CLR用於預防因事務回滾過程當中出現故障形成影響,當事務回滾時,每回滾一條日誌就記錄一條CLR,系統能夠經過CLR判斷哪些操做已經回滾,若是不記錄CLR則可能出現操做回滾兩次的狀況。

在正常記錄日誌時,ARIES會記錄redo和undo信息,記錄的日誌包含修改先後的值等。通常來講,日誌落盤是順序寫,所以數據庫在配置上會爲日誌服務單獨安排磁盤,不和存儲數據記錄的盤混用,以提高日誌寫的性能。

下面是ARIES中日誌落盤示意圖,圖中右側序列表明全部日誌,青藍色部分表明已經落盤的日誌,橙色部分表示還在日誌緩衝區裏的日誌。ARIES會記錄Flushed LSN,表明目前已有哪些緩衝區的日誌已經刷到磁盤。此外,保存數據的每一個磁盤塊中都會記錄一個Page LSN,用來表示修改此數據Page的全部操做中對應的最大日誌號(即最後一個修改數據Page的操做所對應的日誌號)。在把數據緩衝區裏的數據刷到磁盤時,經過判斷Page LSN與flushed LSN的大小決定是否能夠將數據刷到磁盤。若是Page LSN 小於等於Flushed LSN ,說明修改這個數據頁面的全部日誌記錄都已落盤,所以數據也能夠落盤,這就是所謂的WAL(Write-Ahead-Log),日誌老是先於數據寫到磁盤。

此外,日誌記錄中還保存了Prev LSN來對應日誌所屬事務的前一個日誌號。因爲在系統中全部事務共享日誌緩衝區,所以產生的日誌是穿插在一塊兒的,能夠經過Prev LSN把屬於同一個事務的全部LSN串聯起來,來找到事務所對應的全部日誌

恢復子系統中還須要維護Xact Table和Dirty Page Table。Xact Table用來記錄全部活動的Transaction的狀態如active、commit、abort、end等;同時還記錄事務最後產生的日誌號Last LSN。Dirty Page Table用來記錄哪些數據Page從磁盤上加載到緩衝區後被修改過, 以及每一個Page最先修改時的日誌號Rec LSN(即數據Page被加載到緩衝區後第一個修改操做所對應的日誌號)。

除了在日誌中記錄信息外,爲保證恢復能夠成功完成,數據庫系統還須要用Master Record記錄Checkpoint的LSN,保證在每次恢復時只須要從最近的Checkpoint開始便可。因爲數據庫系統在作Checkpoint時須要停機(不容許任何事務執行),這對於使用者很難接受,所以ARIES中的Checkpoint採用Fuzzy Checkpoint方式,即在進行Checkpoint時容許事務能夠持續不斷執行。Fuzzy Checkpoint會產生兩個日誌記錄:Begin_Checkpoint和End_Checkpoint。Begin_Checkpoint負責記錄開始Checkpoint的時間點,End_Checkpoint記錄Xact Table和Dirty Page Table,而Checkpoint的LSN會寫到磁盤的Master Record上進行持久存儲。以上即恢復所需的所有數據結構,各種LSN的整理總結以下表所示

—數據庫系統的事務恢復—

  • 簡單事務恢復

對於簡單事務恢復(系統沒有出現故障,而是事務在執行過程當中再也不繼續),此時須要進行回滾。回滾時,系統首先從Xact Table中找出最新的LSN進行undo,隨後經過該日誌記錄的Prev LSN找到前序日誌記錄再繼續undo,直到整個事務完全回放到開始時的狀態。和正常事務操做類似,undo時的數據實際上須要加鎖,並在回滾前會記錄補償日誌CLR。CLR會記錄undo next的LSN號以指向下一條須要undo的LSN,在undo到Transaction Start的LSN時,記錄Transaction Abort和Transaction End代表回滾結束。

  • 出現故障的事務恢復

在前文咱們提到,ARIES的故障恢復分爲三個階段,下面將詳細介紹三個階段的執行細節。

  1. Analysis階段

    在Analysis階段,系統從磁盤上的Master Record中獲取最後一個Checkpoint日誌記錄,重構出Xact Table和Dirty Page Table,並從Begin_Checkpoint日誌記錄開始順序處理後續的日誌記錄。在遇到一個事務的end日誌時,將其從Xact Table中去除;若是遇到事務的commit日誌,則更新Xact Table中對應事務的狀態;若是遇到其它日誌記錄,判斷該事務是否在Xact Table中,不在則將其加入Xact Table,並更新Xact Table中該事務的Last LSN爲當前日誌記錄的LSN。此外,系統會判斷日誌記錄中更新的數據Page是否在Dirty Page Table,如不在則將該數據Page加入到Dirty Page Table,並將其Rec LSN設爲當前日誌號。

  2. Redo階段

    系統在Redo階段首先找出Dirty Page Table中全部PageRec LSN中最小的,做爲redo的起始位置,由於再往前的日誌記錄對應的數據修改都已落盤,不會出如今Dirty Page Table中。隨後系統從redo的起始位置開始,按順序對後續更新日誌記錄(包括CLR)執行redo操做(重放)。若是遇到操做更新的Page不在Dirty Page Table中,或Page在Dirty Page Table中但Rec LSN大於當前LSN,或磁盤上的Page LSN大於當前的LSN,則都表示該LSN對應記錄已經落盤,能夠直接跳過,不須要執行redo。在redo時,系統不須要再記錄日誌,由於redo只是實現整個內存狀態的重構,若是在redo時又出現了系統故障,則按照原來操做從新進行一遍。

3.Undo階段

Undo階段目的是撤銷在系統故障時未完成的事務,開始時會創建一個須要undo的日誌集合,把每一個須要回滾的事務的最後一條日誌號放入該集合中,而後開始進行循環處理。首先系統從集合裏挑出最大的LSN即最後一條進行undo,若是這條日誌是CLR補償日誌,且它的undo-next爲空,那麼說明事務已經完成undo,能夠記錄一條End日誌代表事務結束;若是補償日誌的undo-next不等於空,說明還有下一條須要undo的日誌,那麼就將下一條日誌的LSN放入集合;若是是更新日誌,就回滾該日誌且記錄一條CLR日誌,而後把日誌的Prev LSN加入集合。系統會按照上述過程不斷循環,直到整個undo集合爲空。

接下來經過例子梳理一下整個過程。系統首先作了Fuzzy Checkpoint,出現了兩次更新:T1修改了P5,T2修改了P3。隨後,T1 abort 取消,LSN40記錄了補償日誌——回滾LSN10,隨後T1 End。接下來其餘事務繼續進行:T3修改了P1,T2修改了P5。此時出現了Crash,該怎麼作恢復呢?首先在Analysis過程,由Checkpoint開始向後掃描,發現T1已經End不須要redo,T二、T3沒有end能夠進行redo,所以Xact Table裏僅有T2 、T3,Dirty Page Table包括P一、P三、P5。在分析完成後,進行redo重作過程恢復故障現場,隨後在T二、T3進行undo每一條日誌時記錄CLR,直到undo到每一個事務最初的一條

若是在恢復的過程當中又出現了Crash(以下圖所示),已經undo的兩個操做因爲記錄了CLR,新redo會重作這兩個CLR,而新undo過程不會再從新回滾。恢復系統會在原有基礎上繼續進行,直到全部的事務所有undo完成。

  • ARIES小結

ARIES是一個具備成熟設計,可以保證事務原子性和持久性的恢復系統,使用WAL和Steal + No Force緩衝區管理策略,且不影響系統正確性。ARIES中LSN是單調遞增的日誌記錄惟一標識,經過連接方式把一個事務的全部日誌串聯在一塊兒。Page LSN用來記錄每一個頁面最後修改操做對應的日誌號,系統經過Checkpoint減小Recovery的開銷。整個恢復分爲Analysis、Redo、Undo三個步驟,分析的目的是找出來哪些事務須要redo,哪些頁面被修改過,修改是否已經落盤;隨後經過redo恢復故障現場,利用undo將須要撤銷的事務回滾。

—本文小結—

本文介紹了恢復系統Logging和Recovery的基本概念,並討論了傳統基於磁盤的數據庫管理系統中恢復子系統ARIES的技術原理。下一篇文章會繼續探索數據庫的恢復子系統,討論DBMS恢復中的Early Lock Release、Logical Undo,介紹兩種數據庫的恢復技術以及內存數據庫的恢復方法。

 

參考文獻:

1. C. Mohan, Don Haderle, Bruce Lindsay, Hamid Pirahesh, and Peter Schwarz. 1992. ARIES: A Transaction Recovery Method Supporting Fine-Granularity Locking And Partial Rollbacks Using Write-Ahead Logging. ACM Trans. Database Syst. 17, 1 (March 1992), 94–162. 

2. Antonopoulos, P., Byrne, P., Chen, W., Diaconu, C., Kodandaramaih, R. T., Kodavalla, H., ... & Venkataramanappa, G. M. (2019). Constant time recovery in Azure SQL database. Proceedings of the VLDB Endowment, 12(12), 2143-2154.

3. Zheng, W., Tu, S., Kohler, E., & Liskov, B. (2014). Fast databases with fast durability and recovery through multicore parallelism. In 11th {USENIX} Symposium on Operating Systems Design and Implementation ({OSDI} 14) (pp. 465-477).

4. Ren, K., Diamond, T., Abadi, D. J., & Thomson, A. (2016, June). Low-overhead asynchronous checkpointing in main-memory database systems. In Proceedings of the 2016 International Conference on Management of Data (pp. 1539-1551).

5. Kemper, A., & Neumann, T. (2011, April). HyPer: A hybrid OLTP&OLAP main memory database system based on virtual memory snapshots. In 2011 IEEE 27th International Conference on Data Engineering (pp. 195-206). IEEE.

相關文章
相關標籤/搜索