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

星環科技發表於2021-02-02
— 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和長度,以及修改前後的值。

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

  • 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對於P1、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,T2、T3沒有end可以進行redo,因此Xact Table裡僅有T2 、T3,Dirty Page Table包括P1、P3、P5。在分析完成後,進行redo重做過程恢復故障現場,隨後在T2、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.


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69994106/viewspace-2755562/,如需轉載,請註明出處,否則將追究法律責任。

相關文章