博客 > 一篇文搞懂Undo Log(重做日志)和 Redo Log(回滾日志)
瀏覽量:3053次評論:0次
作者:銳成網(wǎng)絡(luò)整理時間:2024-08-13 17:52:23
在數(shù)據(jù)庫中Undo Log(重做日志)和 Redo Log(回滾日志)是兩個非常重要的概念,為了方便大家更好的了解他們,我們將詳細介紹Undo Log和 Redo Log概念和區(qū)別。不過在搞懂Undo Log和 Redo Log之前,我們先了解幾個概念。
事務(wù)和ACID
我們學(xué)數(shù)據(jù)庫的時候經(jīng)??吹绞聞?wù)和ACID的說法。
什么是事務(wù)呢?
在數(shù)據(jù)庫系統(tǒng)中,一個事務(wù)是指:由一系列數(shù)據(jù)庫操作組成的一個完整的邏輯過程。
例如銀行轉(zhuǎn)帳:
1.從原賬戶扣除金額;
2.向目標(biāo)賬戶添加金額。
這兩個數(shù)據(jù)庫操作的總和,構(gòu)成一個完整的邏輯過程,不可拆分。這個過程被稱為一個事務(wù),具有ACID特性。
那什么又是ACID呢?
維基百科上ACID的定義如下:
ACID,是指數(shù)據(jù)庫管理系統(tǒng)(DBMS)在寫入或更新資料的過程中,為保證事務(wù)(transaction)是正確可靠的,所必須具備的四個特性:原子性(atomicity,或稱不可分割性)、一致性(consistency)、隔離性(isolation,又稱獨立性)、持久性(durability)。
其實原子性、隔離性、持久性的最終目的就是為了數(shù)據(jù)的一致性。
如何實現(xiàn)原子性和持久性?
原子性保證了一個事務(wù)中的多個操作要么都成功,要么都失敗,不存在成功一半的情況。持久性保證了事務(wù)一旦生效,就不會因為任何原因?qū)е聰?shù)據(jù)被修改或者丟失。
那么如果才能實現(xiàn)原子性和持久性呢?
我們很容易就能想到,數(shù)據(jù)庫把數(shù)據(jù)寫入磁盤不就行了嗎?
是的,這是正確的方法,但問題是“寫入磁盤”這個操作不是原子的,寫操作可以有開始寫入、寫入中、寫入成功,甚至還有寫入失敗等狀態(tài)。
而且一個事務(wù)中經(jīng)常包含多個操作,比如我們?nèi)ゾW(wǎng)上下單買東西,一般涉及到這幾個操作:從我們的賬戶中扣款、在商家的賬戶增加貨款、把商品的庫存減掉等等。這些操作是在一個事務(wù)中的,也就是說要么全部成功,要么全部失敗。
崩潰恢復(fù)
如果我們的賬戶中扣了100塊錢,這個操作成功寫入了磁盤,而在給商家增加100塊錢的時候系統(tǒng)崩潰了(這么倒霉?),或者停電了(不會吧?),導(dǎo)致寫入失?。ń?jīng)常會出現(xiàn)吧?)。
為了避免這種情況發(fā)生,數(shù)據(jù)庫就得想辦法知道系統(tǒng)崩潰前完整的操作是怎么樣的,這樣等服務(wù)器恢復(fù)后,數(shù)據(jù)庫要把還沒來得及寫入磁盤的那一部分?jǐn)?shù)據(jù)重新寫入,給商家的賬號上加100塊錢,完成未竟的事業(yè)。
那么問題來了,系統(tǒng)恢復(fù)后數(shù)據(jù)庫如何知道之前事務(wù)的所有信息呢?
好記性不如爛筆頭,我們先寫下來不就行了嗎?
Redo Log(回滾日志)
這就要求數(shù)據(jù)庫在寫磁盤之前要把事務(wù)所有的操作都先記錄下來,比如修改什么數(shù)據(jù)、數(shù)據(jù)物理上位于哪個內(nèi)存頁和磁盤塊中、從什么值改成什么值等等,以日志的形式先寫到磁盤中。
只有在日志記錄全部都安全落盤,然后在最后寫上“Commit Record”后,表示所有的操作記錄我都寫完啦。
這時候數(shù)據(jù)庫才會根據(jù)日志上的信息,對真正的數(shù)據(jù)進行修改,修改完成后,在日志中加入一條“End Record”,表示我已經(jīng)按照日志里的步驟都做完啦,事務(wù)持久化的工作也就做完了。
這種事務(wù)實現(xiàn)方法被稱為“Commit Logging”。
這種方式實現(xiàn)數(shù)據(jù)持久性、原子性的原理如下:
首先, 一旦日志成功寫入了Commit Record,那就表示事務(wù)相關(guān)的所有信息都已經(jīng)寫到日志中了,如果修改數(shù)據(jù)的過程中系統(tǒng)崩潰了,重啟后只要再根據(jù)日志的內(nèi)容重新操作一遍就行了,這就保證了持久性。
其次,如果日志還沒寫完系統(tǒng)就崩潰了,系統(tǒng)重啟后,數(shù)據(jù)庫一看日志里沒有Commit Record,這話就說明日志是不全的,還沒有寫完,那么就將這部分日志標(biāo)記為回滾狀態(tài),整個事務(wù)就回滾了,這就保證了原子性。
換句話說就是,我先把我要改的東西記錄在日志里,我再根據(jù)日志統(tǒng)一寫到磁盤中,萬一我在寫入磁盤的過程中暈倒了,等我醒來的時候,我先查看日志的完整性。
如果日志是完整的,里面有Commit Record,我就照著日志重新做一遍,最后也能成功。如果日志是不完整的,里面沒有Commit Record,我就回滾整個事務(wù),什么都不做。
這個日志就叫做 Redo Log,也就是“重做日志”,中途崩潰的數(shù)據(jù)庫,根據(jù)這個日志把事務(wù)重做一遍。
Undo Log(重做日志)
不過Redo Log有個問題,就是效率太慢。
因為數(shù)據(jù)庫對數(shù)據(jù)的所有真實修改,都必須發(fā)生在事務(wù)提交之后,并且在日志寫入了 Commit Record 之后才能進行,沒有寫完Redo Log,數(shù)據(jù)庫是不敢先寫的。
即使事務(wù)提交前磁盤 I/O 有足夠空閑、即使某個事務(wù)修改的數(shù)據(jù)量非常龐大,占用大量的內(nèi)存緩沖,無論何種理由,都決不允許在事務(wù)提交之前就開始修改磁盤上的數(shù)據(jù),萬一系統(tǒng)崩潰了,數(shù)據(jù)出差誰負(fù)責(zé)呀?
但是當(dāng)一個事務(wù)中數(shù)據(jù)量特別大的時候,等全部變更寫入Redo Log然后再統(tǒng)一寫入磁盤,這樣性能就不是很好,就會很慢,老板就會不開心。
那能不能在事務(wù)提交之前,偷偷地先寫一點數(shù)據(jù)到磁盤呢(偷跑)?
答案是可以的,這就是STEAL策略,但是問題來了,你偷摸地寫了數(shù)據(jù),萬一事務(wù)要回滾,或者系統(tǒng)崩潰了,這些提前寫入的數(shù)據(jù)就變成了臟數(shù)據(jù),必須想辦法把它恢復(fù)才行。
這就需要引入Undo Log(回滾日志),在偷摸寫入數(shù)據(jù)之前,必須先在Undo Log中記錄都寫入了什么數(shù)據(jù),改了什么地方,到時候事務(wù)回滾了,就按照Undo Log日志,一條條恢復(fù)到原來的樣子,就像沒有改過一樣。
Undo Log還有一個作用,就是實現(xiàn)多個行版本控制(MVCC),當(dāng)讀取的某一行被其他事務(wù)鎖定時,它可以從 Undo Log 中獲取該行記錄以前的數(shù)據(jù)是什么,從而提供該行版本信息,讓用戶讀取。
總結(jié)
Undo Log(重做日志) 和 Redo Log(回滾日志)之間的區(qū)別,沒那么高深,我們只要按字面意思理解就行了。
Redo Log(重做日志)是為了系統(tǒng)崩潰之后恢復(fù)數(shù)據(jù)用的,讓數(shù)據(jù)庫照著日志,把沒做好的事情重做一遍。 有了Redo Log,就可以保證即使數(shù)據(jù)庫發(fā)崩潰重啟后,之前提交的記錄都不會丟失,這個能力稱為 crash-safe。
Undo Log(回滾日志)是為了回滾用的。 在事務(wù)提交之前就開始寫數(shù)據(jù),萬一事務(wù)到最后又打算不提交了,要回滾,或者系統(tǒng)崩潰了,這些提前寫入的數(shù)據(jù)就變成了臟數(shù)據(jù),這時候就必須用Undo Log恢復(fù)了。
這種在寫磁盤之前先寫日志的方式就叫做:Write-Ahead Logging(WAL),WAL讓性能更高了,不過同時也更復(fù)雜了,雖然復(fù)雜點,但是效果很好,mysql、sqlite、postgresql、sql server等數(shù)據(jù)庫都實現(xiàn)了WAL機制。
重要聲明:本文來自編程我也會,經(jīng)授權(quán)轉(zhuǎn)載,有部分增減,版權(quán)歸原作者所有,不代表銳成觀點,轉(zhuǎn)載的目的在于傳遞更多知識和信息。
相關(guān)文章推薦
2025-05-27 11:53:22
2024-08-20 17:58:16
2024-08-19 17:49:29
2024-08-19 10:23:28
2024-08-16 17:06:33
熱門工具
標(biāo)簽選擇
閱讀排行
我的評論
還未登錄?點擊登錄