走近數(shù)據(jù)恢復(fù)
2020-07-21 19:34:17
供稿:網(wǎng)友
我常常在想,如果數(shù)據(jù)庫不用考慮數(shù)據(jù)恢復(fù),對我們這些做數(shù)據(jù)庫的人來說,日子也許將變過美好很多。
沒有一種軟件會象數(shù)據(jù)庫這樣,需要面對如此惡劣的環(huán)境。你需要考慮各種可能的錯誤和故障,例如系統(tǒng)斷電、磁盤損壞、甚至是地震火災(zāi)。而給你的目標非常明確:不論發(fā)生何種故障,數(shù)據(jù)都不能被丟失,你可能覺得這有些小題大做,可對于許多商業(yè)應(yīng)用(如銀行、火車訂票系統(tǒng)等)來說,這只不過是最基本的要求。
要保證每一步操作都不會丟失,既無必要,也無可能(除非你能發(fā)明一種和硬盤一樣大,和內(nèi)存一樣快,同時斷電時數(shù)據(jù)不丟失的東東)。因此同并發(fā)控制中一樣,數(shù)據(jù)庫同樣也利用了事務(wù)的概念。事務(wù)是這樣一組操作,這組操作要么都做,要么都不做(我們通常把這叫做事務(wù)的原子性)。而當你決定結(jié)束一個事務(wù)時,你可能會選擇:是提交(COMMIT)這個事務(wù),還是應(yīng)該滾回(ROLLBACK)它。如果你選擇提交,那么你在這個事務(wù)中所做的全部修改都會被存入數(shù)據(jù)庫中,如果這個數(shù)據(jù)庫系統(tǒng)足夠強壯,它將保證:只要事務(wù)提交完成,不管今后發(fā)生何種故障,事務(wù)所做的修改都不會丟失。如果你選擇滾回,那么系統(tǒng)將回到事務(wù)開始的狀態(tài),你在該事務(wù)中所做的所有修改都將丟失。如果在事務(wù)運行當中,系統(tǒng)發(fā)生了任何故障,你會期望它的結(jié)果應(yīng)該和你滾回這個事務(wù)一樣。
恢復(fù)的本質(zhì)是數(shù)據(jù)的冗余,在眾多的冗余手段中,日志(log)也許是我們最常使用的技術(shù)(盡管我們還有許多其它的選擇,如影子頁面等)。在我們對數(shù)據(jù)庫進行修改之前,系統(tǒng)會將數(shù)據(jù)修改前的影象(前項)和你要修改的數(shù)據(jù)影象(后項)保存在日志當中。在這個過程中,有兩點需要保證。一是日志必須先于它對應(yīng)的修改被寫入數(shù)據(jù)庫,我們把這叫做先寫日志(WAL)協(xié)議,這很容易理解,想象一下,如果修改被先寫入數(shù)據(jù)庫,而系統(tǒng)在日志被寫入之前崩潰了,那么它將無法把該事務(wù)恢復(fù)到開始的狀態(tài)。二是在事務(wù)提交之前,必須將它的日志寫入數(shù)據(jù)庫。否則,系統(tǒng)無法保證后續(xù)的故障不會丟失該事務(wù)的修改。我們將不能實現(xiàn)我們在前面對用戶所做出的承諾。
我們繼續(xù)上文的討論,看看我們到底有哪些故障需要應(yīng)付。
首先是應(yīng)用故障,例如用戶不小心錯刪了一張表,或者應(yīng)用破壞了完整性約束。這種故障的恢復(fù)非常簡單,對于前者,你可以顯式地滾回事務(wù)(利用日志的前項),如果你不小心提交了事務(wù),那么問題就麻煩了,系統(tǒng)也許只能把它當作介質(zhì)故障(利用備份)來恢復(fù)了;對于后者,系統(tǒng)會強迫把該事務(wù)滾回。只要數(shù)據(jù)庫還在運行,在系統(tǒng)看來,事務(wù)的滾回與其它正常操作并沒有什么區(qū)別。
然后是進程故障,假如在系統(tǒng)運行時,一個client崩潰了,或者網(wǎng)絡(luò)斷了(通常服務(wù)器無法區(qū)別這兩種狀態(tài));或者服務(wù)器端的某個進程死了。這時我們恐怕得為系統(tǒng)配置一個監(jiān)視進程,由它來定期地檢查系統(tǒng)狀態(tài),恢復(fù)或清除失敗的進程(連接),同時把對應(yīng)的事務(wù)滾回。我們會希望這個監(jiān)視進程是所有進程的父進程,因此假設(shè)連它也死了,我們就能把這種情況歸結(jié)到后面將要討論的系統(tǒng)故障。
接著是系統(tǒng)故障,假如系統(tǒng)因為內(nèi)部錯誤(例如數(shù)據(jù)庫或操作系統(tǒng)含有bug),或者發(fā)生斷電。這時緩沖區(qū)里的數(shù)據(jù)全部丟失,但幸運地是磁盤上的數(shù)據(jù)還在。因此系統(tǒng)在重新啟動(RESTART)后,首先重做所有事務(wù)的修改(利用日志的后項),這就讓數(shù)據(jù)庫回到了發(fā)生故障時的狀態(tài),這時再將所有在這一點上未提交的事務(wù)滾回就完事了。注意這一過程是自動完成的,你完全不需要去關(guān)心它。
再接著是介質(zhì)故障,假如磁盤出現(xiàn)了壞磁道,或者整個磁盤報銷了。這時上面的數(shù)據(jù)肯定已經(jīng)丟失了。由于介質(zhì)故障只能在你試圖再次存取磁盤時被發(fā)現(xiàn),而這時故障可能早已發(fā)生。因此對介質(zhì)故障的恢復(fù)需要你的參與才能完成。你必須定期地備份(BACKUP)數(shù)據(jù)庫,這樣,當介質(zhì)故障發(fā)生時,你可以先用備份重新覆蓋整個數(shù)據(jù)庫(RESTORE過程),然后利用日志重做從備份那點到當前的數(shù)據(jù)庫的更新(ROLL-FORWARD過程),接下來的事情就和系統(tǒng)故障完全一樣了。你可能會問,那要是日志也壞了怎么辦呢?沒辦法,雞生蛋、蛋生雞,總得有個頭吧。所以你最好祈禱日志不要壞,為了保證這一點,你應(yīng)該對日志文件進行鏡象,或者干脆用RAID。
除了這種恢復(fù)方式,我們還有一種叫做邏輯恢復(fù)的方式,也就是利用我們常常在用的IMPROT/EXPORT工具對數(shù)據(jù)進行備份/恢復(fù)。當然我們只把它看作是介質(zhì)故障恢復(fù)的一種輔助形式(也許它更適合于恢復(fù)我們前面說的那種應(yīng)用故障),因為你只能把數(shù)據(jù)恢復(fù)到你備份的那一點。
最后是災(zāi)難,象發(fā)火災(zāi)、被人黑了什么的,這時整個系統(tǒng)可能被完全破壞。你當然仍然可以對數(shù)據(jù)庫進行備份,然后把備份(磁盤)放到另一個安全的地方,但這樣做,備份以后數(shù)據(jù)庫所做的修改可能就永久丟失了。一個更為穩(wěn)妥的辦法是我們在遠程建立一個備份系統(tǒng),所有在本地產(chǎn)生的日志同時也送往這個遠程系統(tǒng),為了防止網(wǎng)絡(luò)發(fā)生故障,本地與遠程系統(tǒng)之間應(yīng)該同時建立幾條相互獨立的網(wǎng)絡(luò)連接。這聽上去好象有點超前,可實際上許多關(guān)鍵應(yīng)用早就用上了。
應(yīng)該明白的是,恢復(fù)畢竟是一種非常耗時的工作,特別是進行后三種故障的恢復(fù)時,數(shù)據(jù)庫對用戶不可用。而這對象銀行這樣的部門來說,損失實在太大了。因此在很多情況下,我們只把恢復(fù)看作是最后的一道防線,我們希望最好永遠也別需要用到它。因此現(xiàn)在就出來了各種各樣的容錯設(shè)備,象RAID、雙機系統(tǒng)什么的,它們會把故障發(fā)生的概率降低到一個實際上可能永不發(fā)生的程度。