《數(shù)據(jù)庫故障恢復(fù)機制的前世今生》[1]一文中介紹過,由于磁盤的的順序訪問性能遠好于隨機訪問,數(shù)據(jù)庫設(shè)計中通常都會采用WAL的方式,將隨機訪問的數(shù)據(jù)庫請求轉(zhuǎn)換為順序的日志IO,并通過Buffer Pool盡量的合并并推遲真正的數(shù)據(jù)修改落盤。如果發(fā)生故障,可以通過日志的重放恢復(fù)故障發(fā)生前未刷盤的修改信息。也就是說Log中包含數(shù)據(jù)庫恢復(fù)所需要的全部信息。
現(xiàn)代數(shù)據(jù)庫為了追求更高的事務(wù)并發(fā)度,會顯式地區(qū)分用戶可見的邏輯內(nèi)容和維護內(nèi)部的物理結(jié)構(gòu),在并發(fā)控制上支持了Lock和Latch的分層,同時也在故障恢復(fù)上區(qū)分了User Transaction和System Transaction。在這種設(shè)計下, 保證數(shù)據(jù)庫D(Durable)的Redo Log需要能在Crash Recovery的過程中,在完全不感知用戶事務(wù)的情況下,恢復(fù)未提交的System Transaction。因此,Redo Log的設(shè)計上天然就是Page Oriented的,也就是說每條Redo Log都被限制在單個Page中,其重放過程不需要感知用戶事務(wù)的存在,也不需要關(guān)心其他的Page。在《B+樹數(shù)據(jù)庫故障恢復(fù)概述》[2]中詳細(xì)的討論過這個過程,也提到這樣做的好處使得在Crash Recovery的過程中Page的恢復(fù)過程可以實現(xiàn)充分的并發(fā)。到這里我們就可以引出本文想要討論的主要內(nèi)容:
已知:
特性1(完備):Log中包含數(shù)據(jù)庫恢復(fù)所需要的全部信息;
特性2(Page Oriented):Page通過Log的恢復(fù)過程只需要關(guān)心當(dāng)前的Page本身;
那么,通過這兩個特性,數(shù)據(jù)庫設(shè)計能實現(xiàn)哪些實用和有趣的功能呢?
Single Page Recovery
最直接的就是讓Single Page Recovery成為可能,當(dāng)硬件故障導(dǎo)致某些Page的數(shù)據(jù)損壞或錯誤時,通常數(shù)據(jù)庫都是將這類Page異常直接當(dāng)做介質(zhì)損壞來處理的,比如需要從最近的備份做還原。這樣會由于多余的,不必要的數(shù)據(jù)還原導(dǎo)致較長的恢復(fù)時間和空間開銷。而Single Page Recovery可以更精準(zhǔn)、更快的只恢復(fù)損壞的Page。如果再搭配上一些Page Corruption檢測機制,比如磁盤、操作系統(tǒng)、DB對數(shù)據(jù)的Checksum檢查,甚至是一些自檢的數(shù)據(jù)結(jié)構(gòu),就可以實現(xiàn)更可靠的數(shù)據(jù)庫服務(wù)。
為Log建立按Page索引(Log Index)
發(fā)現(xiàn)損壞的Page后,下一步就是對該Page的恢復(fù),即Single Page Recovery過程本身。這個時候最主要的是需要有根據(jù)Page號查找所有需要的Log的能力。而正常的Log寫入是Append Only的,所有Page的Log會穿插在一起,因此這里需要Log有按照Page的索引存在。比如,可以通過在Log中添加信息維護如下Page的Log鏈,當(dāng)需要恢復(fù)Page時,可以沿著這個Log鏈一路找到所有需要的Log Record:
More Than Single Page Recovery
Single Page Recovery其實是讓DB擁有了:在任何時候,通過較老的Page版本及之后的Log,在線獲得Page的最新版本的能力。 那么,利用和這個能力,DB能做的就不只是單個Page的故障恢復(fù)。甚至轉(zhuǎn)變一下思路,如果通過主動的引入Page故障,并在需要的時候再做這個Page的Recovery是否能獲得更多的東西呢?本文將從這個角度出發(fā)介紹幾個DB可能的工作,其中很多其實已經(jīng)在慢慢變成包括PolarDB在內(nèi)的現(xiàn)代數(shù)據(jù)庫的標(biāo)配。
寫省略(Write Elision):
省略部分Page刷盤操作,主動讓Page成為“Corrupt Page”, 并在需要的使用再通過Single Page Recovery來拿到需要的Page。
快速重啟(Instant Recovery):
當(dāng)發(fā)生System Failure后,DB重啟過程中,跳過需要的Log應(yīng)用,主動保持這些Page的“Corrupt”狀態(tài),在后續(xù)需要訪問的時候再通過Single Page Recovery恢復(fù)。
快速還原(Instant Restore):
當(dāng)發(fā)生Media Failure后,DB還原的過程中,跳過Page的修復(fù)過程,同樣在后續(xù)需要時再恢復(fù)。
寫省略(Write Elision)
一次很小的Page修改通常會對應(yīng)一條很短的Log Record,但卻會導(dǎo)致整個Page在Buffer Pool中變成臟頁,在《庖丁解Innodb之Buffer Pool》[3]中介紹過,Buffer Pool本身大小是受限的,當(dāng)沒有空閑的Page空間時,為了承載新的請求,就需要通過例如LRU算法來選擇Page換出,如果換出的Page本身是臟頁,就需要先將這個臟頁刷盤,也就是觸發(fā)一次Page大小的寫IO。當(dāng)總數(shù)據(jù)量遠大于Buffer Pool的場景中,這種現(xiàn)象頻繁的發(fā)生:每個Page被換入Buffer Pool后做了很少的修改,又很快因為被換出而刷盤。很小的修改導(dǎo)致很大的寫IO,而IO的帶寬資源又是很寶貴的,這種場景中很容易就變成了整個DB的性能瓶頸,這也就是所謂的IO-Bound場景。
Single Page Recovery給了這種場景一種新的選擇,當(dāng)臟頁被換出時,直接跳過刷臟過程,從而完全避免了Page大小的IO。當(dāng)下次該Page再次被換入時,這個Page會被看做是一個“Corrupt Page”,通過Log的按Page索引找到需要的Log Record,并完成應(yīng)用。這種實現(xiàn)由于避免了大量的Page IO,可以顯著的提升這種IO-Bound場景下的DB性能。這種實現(xiàn)中,可以在寫入過程中,在內(nèi)存中維護Log的按Page索引。
快速重啟(Instant Recovery)
數(shù)據(jù)庫發(fā)生故障或運維操作需要重啟時,中斷服務(wù)的時間直接影響數(shù)據(jù)庫的可用性,因此這個階段是希望盡可能短暫的。《數(shù)據(jù)庫故障恢復(fù)機制的前世今生》[1]中介紹過,ARIES實現(xiàn)的數(shù)據(jù)庫在恢復(fù)過程中會經(jīng)歷Log Analysis、Redo Phase以及Undo Phase三個階段,其中回滾未提交事務(wù)的Undo階段可以在數(shù)據(jù)庫提供服務(wù)之后,在后臺進行。
因此主要影響不可服務(wù)時間的,就是Log Analysis階段及Redo Phase階段,其中應(yīng)用Log恢復(fù)Page的Redo Phase的時間占比又顯著高于僅僅掃描Redo的Log Analysis階段。實踐中,Redo Phase的時間可能因為Active Redo的量及Buffer Pool的大小限制變得不可接受。Redo Phase主要的任務(wù)是要將所有的未刷盤的Page通過重放Redo恢復(fù)到最新的狀態(tài),如果我們暫時接受這種未恢復(fù)Page的“Corrupt”狀態(tài),并利用Single Page Recovery的能力,在需要的時候再在后臺完成,那么,我們就可以將數(shù)據(jù)庫提供服務(wù)的時間提前到Redo Phase開始之前,如下圖所示:
重啟階段
為了實現(xiàn)快速重啟,在ARIES的基礎(chǔ)上,Log Analysis階段需要額外維護一些必要的信息,主要包括Register Pages及Log Index。其中Register Pages中記錄所有Checkpoint之后的Active Redo所涉及到的Page,這些是所有需要恢復(fù)的Page。DB提供服務(wù)后,在后臺異步完成Redo Phase之前,如果有用戶請求訪問到Register Pages中的Page才需要觸發(fā)Single Page Recovery的恢復(fù)流程,并在Page恢復(fù)完成后從Register Pages中刪除。另一個需要的信息就是Single Page Recovery過程中需要的Log index,參考ARIES中為Undo Phase維護的Per-Transaction Log鏈,這里也可以維護出Per-Page Log鏈,如下圖所示:
需要做Recovery的Page可以沿著這個鏈表,一路找到當(dāng)前Page LSN的位置或者找到Page Initial位置為止,并順序應(yīng)用所有需要的Page。
后臺Redo Phase
DB完成Log Analysis并開始提供服務(wù)之后,后臺的Redo Phase會比之前同步的Redo Phase有更多的選擇。比如,是立刻恢復(fù)所有的Resister Pages,還是等待這些Page真正被用戶請求使用時再恢復(fù),亦或是二者結(jié)合。又比如,是按照Log中Page的排列順序恢復(fù),還是按照Page的某種優(yōu)先級恢復(fù)(大/小事務(wù)優(yōu)先、大/小表優(yōu)先,或者某種用戶定義的優(yōu)先級),亦或是多種策略相結(jié)合。同時后臺Redo Phase過程由于Page恢復(fù)之間相互獨立,也天然更容易實現(xiàn)并發(fā)。因此,更高的靈活度和可能更高的并發(fā)度,也是Instant Recovery除了快速恢復(fù)服務(wù)之外新增優(yōu)勢。
不過需要注意的是,由于在恢復(fù)同時接受用戶新的請求,完整的恢復(fù)過程可能會拉長,而在這個過程中,用戶請求的性能也是會有下降的,如下圖所示是一個傳統(tǒng)ARIES Restart和Instant Restart的DB可用性及性能效果:
快速還原(Instant Restore)
備份還原通常是數(shù)據(jù)庫應(yīng)對磁盤故障的保底手段。為了實現(xiàn)這一點,正常運行過程中,數(shù)據(jù)庫就需要周期性的對數(shù)據(jù)和日志進行備份,權(quán)衡恢復(fù)時間和對正常運行的影響,其中數(shù)據(jù)備份又包括全量備份和增量備份。當(dāng)遇到磁盤故障需要做備份還原時,會先從全量備份和增量備份在新的磁盤上還原一份數(shù)據(jù),之后應(yīng)用備份時間點之后的日志,全部完成后切換這個新的數(shù)據(jù)庫實例提供服務(wù)。整個過程如下圖所示:
可以看出,備份還原有非常長的周期,包括拷貝全量備份即增量備份的Full Restore及Incremental Restore階段,以及跟重啟類似的Log Analysis、Redo Phase和Undo Pass階段,其恢復(fù)時間跟數(shù)據(jù)及日志總量相關(guān),并受網(wǎng)絡(luò)帶寬及磁盤IO的限制。因此,盡可能讓DB提前提供服務(wù)是非常必要的,類似于上面講的快速重啟,ARIES通過事務(wù)Lock的方式,讓數(shù)據(jù)庫可以在Undo Phase階段完成前就提供服務(wù)。同樣的,我們可以通過暫時接受“Corrupt Page”,將真正的Page Recovery推遲到需要的時候,從而將DB整體提供服務(wù)的時間提前,如下圖所示:
我們甚至可以將這個時間點提前到備份還原的一開始。這個時候,新的磁盤上甚至還沒有任何Page數(shù)據(jù),當(dāng)一個Page被訪問的時候,會先從最近的全量及增量備份中去找到該Page的歷史版本,再從Log備份中找到這個Page之后的所有Log完成應(yīng)用。因此,能夠快速找到需要Page對應(yīng)的備份數(shù)據(jù)位置及需要的增量Logs非常重要,也就是在正常的備份過程中,為備份和Log維護按Page的索引。
為數(shù)據(jù)備份及Log備份建立按Page的索引
正常數(shù)據(jù)庫寫入過程中會以Append Only的方式寫WAL Log,為可能發(fā)生的Crash做Recovery準(zhǔn)備,這里稱為Recovery Log。隨著Checkpoint的推進,陳舊的Recovery Log不再被Recovery需要,可以被清理。但為了可能的備份還原,這部分Log還需要被保留,可能是在成本更低的存儲介質(zhì)上,這部分Log這里稱為Archive Log。在轉(zhuǎn)存Archive Log的過程中,便可以為Archive Log建立按Page索引。最理想的情況是需要還原的時候,有全局的Archive Log索引,但因為Log本身流式產(chǎn)生的特性,這樣顯然是不可能的。因此,分區(qū)排序的Archive Log就成為非常好的選擇,如下圖所示:
后臺的Archive任務(wù)會在內(nèi)存中對順序生成的Recovery Log中的一段按Page排序,這部分內(nèi)存超過某個大小時,已經(jīng)排序的部分會落盤生成一個按Page號有序的Archive Log分片。重復(fù)這個過程就有了許許多多的排序分區(qū)。根據(jù)分片號及Page號就可以訪問到需要Page的所有Archive Log。除了Log以外,為了支持Instant Restore的按需Page恢復(fù),全量備份及增量備份也需要按照Page號建立索引。
最終,如上圖所示,無論是數(shù)據(jù)備份還是日志部分都存在一個索引方式可以方便的按照Page號查找。當(dāng)一個Page需要真正做Restore時,就可以利用這些索引快速找到其對應(yīng)的備份Page版本及后續(xù)Log,完成真正的Page重建。
后臺Restore過程
類似于快速重啟,實踐上通常也會搭配一個后臺運行的Restore任務(wù),即使沒有用戶請求訪問,所有的Page也會在一個有限的時間窗口全部完成Restore。下圖展示的就是從全量備份,增量備份和日志備份中不斷還原Page到目標(biāo)新磁盤的過程。
有了上面所說的數(shù)據(jù)備份及日志備份的按Page索引,后臺的這個Restore過程也可以拋棄之前按Log順序進行的限制,有了更多的選擇和靈活性。舉個很實用的例子,Backup相對于最新的DB位置,受Backup周期及寫入壓力的影響,中間的日志量可能非常多,而這些日志通常又會反復(fù)修改同一個Page,按照Log順序的還原策略,會導(dǎo)致同一個Page可能會不斷的讀寫,造成很大的IO浪費,也因此受到IO帶寬限制。而采用Single Page Recovery方式的后臺Restore過程,天然的可以按照Page的順序進行還原,每個Page的一次讀寫都可以完成全部的日志應(yīng)用,這樣就可能很大程度的提升Page的IO效率和還原的速度。
應(yīng)用 - Aurora
Aurora作為共享存儲數(shù)據(jù)庫的佼佼者,其設(shè)計和實現(xiàn)中大量的利用了日志即數(shù)據(jù)庫的思路。Aurora認(rèn)為計算節(jié)點與存儲節(jié)點分離后,整個DB系統(tǒng)的IO瓶頸會轉(zhuǎn)移到計算節(jié)點與存儲節(jié)點及存儲節(jié)點副本間的網(wǎng)絡(luò)上,為此Aurora的設(shè)計中,計算節(jié)點和存儲節(jié)點,及存儲節(jié)點之間只傳遞日志,如下圖所示:
Aurora也把這種設(shè)計設(shè)計稱為日志即數(shù)據(jù)(The Log is The Database)[4] 。這種實現(xiàn)會在日志量遠小于Page修改量的場景下非常的有效,可以看出網(wǎng)絡(luò)上傳遞的只有Log而沒有任何Page數(shù)據(jù)。每個存儲節(jié)點在收到流式的Log之后,會獨立完成一遍Page的修改過程。下圖所示的是其存儲節(jié)點的工作流程:
存儲節(jié)點不斷的從計算節(jié)點接受Log寫入并持久化90(1),完成日志在Update Queue中的持久化,并返回計算節(jié)點確認(rèn)(2),同其他存儲節(jié)點通信補全Log(3),當(dāng)某些Page收到的連續(xù)日志量超過某個閾值,或者整體的Update Queue中的日志量達到某個閾值后,這些Page會在后臺周期性的應(yīng)用Page的修改并寫入Data Pages,這個過程稱為日志到Page的合并(COALESCE)(5)。最后歷史的日志和數(shù)據(jù)會備份到S3為后續(xù)可能的按時間點還原做準(zhǔn)備。
寫省略(Write Elision)
可以看出,當(dāng)某個Page的收到的日志量比較少的情況下,Aurora的存儲節(jié)點并不基于將其真正的修改到Data Pages中,這個時候,如果計算節(jié)點需要讀這個Page,存儲節(jié)點會應(yīng)用Update Queue中的Log到需要的Page上并返回用戶。這個熟悉的過程其實就是本文提到的寫省略(WRITE ELISION)。理想情況下,一個Page的多次修改對應(yīng)的Log會一直積累在Update Queue中而沒有真正產(chǎn)生Page,直到足夠的Log量觸發(fā)Page 的COALESCE。
快速重啟(Instant Recovery)
由于Aurora的計算節(jié)點不維護Log也不負(fù)責(zé)Page的更新,其重啟過程可以非常迅速,不需要傳統(tǒng)數(shù)據(jù)庫的Log Analysis,Redo Phase及Undo Phase,而這部分需求其實是下放到了存儲節(jié)點上的。Aurora存儲節(jié)點的重啟恢復(fù)過程,第一步要確定VDL or the Volume Durable LSN[5],這個位置可以認(rèn)為對應(yīng)單機數(shù)據(jù)庫的有效Log結(jié)尾,之后這個存儲節(jié)點就可以恢復(fù)向計算節(jié)點提供服務(wù)。這其實就是天然的Instant Restart實現(xiàn),真正的Page Apply被推遲到用戶請求,或收到更多的Log出發(fā)Page的Coalesce。
快速還原(Instant Restore)
云數(shù)據(jù)庫通常都會會提供諸如按時間點還原的功能,來還原一個新的指定歷史時間點的實例。這個過程其實就是典型的備份還原場景,需要結(jié)合歷史的Page版本和后續(xù)增量Log完成。除此之外,Aurora還提供了Backtrack的能力,可以讓當(dāng)前實例分鐘級的快速還原到Backtrack Window內(nèi)的任意時間點,并且這個動作還可以向前向后反復(fù)重復(fù)執(zhí)行。這部分的具體實現(xiàn)細(xì)節(jié)沒有太多的公開資料,不過測試中Aurora在這些功能良好的表現(xiàn)以及合理的實現(xiàn)推測,也讓我們相信其受益于其日志即數(shù)據(jù)庫的設(shè)計。
總結(jié)
本文從AIRES及現(xiàn)代數(shù)據(jù)庫的邏輯、物理分層實現(xiàn),推導(dǎo)出數(shù)據(jù)庫的Redo Log會具有,完備及Page Oriented兩個特性,有了這兩個特性,就可以很好的支持精準(zhǔn)的Single Page Recovery。而更廣泛一點的是讓數(shù)據(jù)庫擁有了:按需在線恢復(fù)單個Page的能力。而利用這個能力并主動引入”Page Corrupt”就可以實現(xiàn)更廣義上的Single Page Recovery。本文從 寫省略(Write Elision)、快速重啟(Instant Recovery)以及快速還原(Instant Restore)三個方向介紹了利用Single Page Recovery可以讓數(shù)據(jù)庫獲得的如性能提升、可用性提高、靈活性提高等優(yōu)勢。最后,通過介紹Amazon的共享存儲數(shù)據(jù)庫Aurora是如何在設(shè)計中應(yīng)用這些優(yōu)化的。最后的最后,同樣作為共享存儲數(shù)據(jù)庫,后起之秀PolarDB與他的前輩Aurora有很多相似的地方,但也有著大不相同的硬件環(huán)境和架構(gòu)設(shè)計,后續(xù)有機會會詳細(xì)介紹PolarDB中是如何利用Single Page Recovery能力獲得這些優(yōu)勢的。
審核編輯:湯梓紅
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1415瀏覽量
41284 -
數(shù)據(jù)庫
+關(guān)注
關(guān)注
7文章
3913瀏覽量
66025 -
日志
+關(guān)注
關(guān)注
0文章
144瀏覽量
10847
原文標(biāo)題:參考
文章出處:【微信號:inf_storage,微信公眾號:數(shù)據(jù)庫和存儲】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
提高Oracle的數(shù)據(jù)庫性能
基于數(shù)據(jù)庫日志復(fù)制和故障恢復(fù)

數(shù)據(jù)庫教程之如何進行數(shù)據(jù)庫設(shè)計

數(shù)據(jù)庫教程之SQL Server數(shù)據(jù)庫管理的詳細(xì)資料說明

盡可能限制NVM寫操作的數(shù)據(jù)庫日志方案NVRC

sql server 數(shù)據(jù)庫顯示正在恢復(fù)怎么辦?
華為云數(shù)據(jù)庫穩(wěn)定可靠-即開即用
【數(shù)據(jù)庫數(shù)據(jù)恢復(fù)】SQL server數(shù)據(jù)庫被加密的數(shù)據(jù)恢復(fù)方案

python讀取數(shù)據(jù)庫數(shù)據(jù) python查詢數(shù)據(jù)庫 python數(shù)據(jù)庫連接
數(shù)據(jù)庫優(yōu)化那些事

SQL Server數(shù)據(jù)庫備份方法
oracle數(shù)據(jù)庫alert日志作用
Oracle數(shù)據(jù)恢復(fù)—異常斷電后Oracle數(shù)據(jù)庫啟庫報錯的數(shù)據(jù)恢復(fù)案例

數(shù)據(jù)庫數(shù)據(jù)恢復(fù)—SQL Server數(shù)據(jù)庫被加密如何恢復(fù)數(shù)據(jù)?

評論