事务日志
轉(zhuǎn)自:http://nosql-wiki.org/foswiki/bin/view/Main/TransactonLog
?
日志保證了數(shù)據(jù)的持久性和事務的原子性。可以簡單的認為日志是一個不斷追加日志記錄的文件。單條日志記錄是一段二進制緩沖區(qū)。 下面是本文會使用到的幾條通用的日志記錄:
- 標示trasaction的開始
- 標示transcatoin成功提交,所有對數(shù)據(jù)的修改都已經(jīng)成功。由于cache的存在,在日志中看到COMMIT并不一定意味著 數(shù)據(jù)的修改都已經(jīng)持久化。日志的目的就是保證所有COMMIT的事務的修改在程序程序異常退出的情況下能夠保留;所有沒有COMMIT 的事務的修改在程序異常退出的情況下都不會保留,就像這些事務根本就沒有START一樣。
- 事務T的所有修改都不能保留下來,最終體現(xiàn)出來的東西就像事務T根本就沒有START過。
日志的類型主要有:undo log,redo log,undo/redo log。最經(jīng)常使用的類型為redo log和undo/redo log。 如果系統(tǒng)不出現(xiàn)異常情況, 那么日志是沒有必要的,因此在講述的時候大部分場景都是指系統(tǒng)異常退出重啟,在敘述過程中不在重復描述這個場景前提。
?
UNDO LOG
日志內(nèi)容
undo log就是把所有沒有COMMIT的事務回滾到事務開始之前的狀態(tài),對于已經(jīng)commit的事務不做任何處理。 因為對于commit的事務不做任何 處理,那么在寫COMMIT日志記錄之前,事務對數(shù)據(jù)的修改都必須已經(jīng)持久化, 如果只有一部分持久化,事務修改的數(shù)據(jù)會處于不一致狀態(tài)。 另外,由于需要做undo操作,因此日志記錄中必須包含數(shù)據(jù)修改前的值, 單條的undo log形式為,表示在事務T開始運行前, X 的值為v;由于對未commit的事務必須進行undo操作,那么在對數(shù)據(jù)庫的數(shù)據(jù)進行修改之前,必須先保證事務日志已經(jīng)持久化, 如果日志沒有持久化,并且最后事務沒有commit,那么數(shù)據(jù)就無法回滾到事務開始前的狀態(tài)。由此可以總結(jié)出undo log必須滿足的兩條規(guī)則:
- U1: If transaction T modifies database element X, then the log record of the form must be written to disk before the new value of X is written to disk.
- U2: If a transaction commits, then its COMMIT log record must be witten to disk only after all database elements changed by the transaction have been written to disk, but as soon thereafter as possible
因此,對于日志和數(shù)據(jù)本身持久化的順序為:
在這里我們可以看到,每個事務commit之前必須把對數(shù)據(jù)的修改進行持久化,這樣會導致性能問題, 因為每次事務都回帶來一次數(shù)據(jù)文件的 sync 寫入,而使用日志的主要目的就是減少磁盤的sync操作。 因此undo log存在較大的性能問題,因此在實際中使用并不太多。
?
日志回放
系統(tǒng)重啟回放日志,只需要從后往前掃描日志文件,對于所有沒有commit的事務按照日志記錄中的數(shù)據(jù)做回滾操作。
?
CheckPoint
按照上述方法回放日志,需要掃描所有日志文件,并且日志文件不能刪除。但是實踐上我們可以看到, 如果一個事務已經(jīng)commit了那么之前的 日志記錄其實就可以不回放了。因此引入checkpoint的概念。
最簡單的checkpoint做法是在做checkpoint的時候阻塞所有更新,直到所有未決的事務都commit活著abort, 然后記錄。在日志回放的時候, 如果碰到就停止回放日志。阻塞更新當然不是優(yōu)雅的處理方式。 下面介紹一種不阻塞更新的checkpoint方法。
生成checkpoint的過程為:
日志回放的時候,如果首先遇到END_CKPT,只需要回放日志到下一個START_CKPT為止,START_CKPT之前的日志可以丟棄;如果首先碰到的是START_CKPT, 只需要回放第一步中記錄的所有事務最早開始的地方,再之前的日志記錄可以直接刪除。
?
REDO LOG
redo log是指在回放日志的時候把已經(jīng)commit的事務重做一遍,對于沒有commit的事務按照abort處理。日志回放并不會處理任何沒有commit的事務, 因此,在COMMIT日志持久化之前,不能將數(shù)據(jù)的修改持久化。因為如果數(shù)據(jù)在COMMIT之前持久化,那么在系統(tǒng)異常退出的情況下,這種部分修改的 事務就會處于一種不一致狀態(tài)。同時,由于重做事務,因此事務日志中必須記錄事務修改以后的值。redo log必須滿足以下規(guī)則:
- R1: Before modifying any database element X on disk, it is necessary that all log records pertaining[附屬于] to this modification of X. including both the update recordand the?record must appear on disk.
redo log與數(shù)據(jù)修改的順序為:
?
日志回放與checkpoint
對于沒有checkpoint的日志回放需要:首先從后往前掃描日志:記錄所有已經(jīng)commit的事務,對于沒有commit的事務在日志末尾追加abort; 然后從前往后掃描日志,redo所有已經(jīng)commit的事務日志。
redo log生成checkpoint的方法:
在從后往前掃描日志文件的時候,如果碰到END_CKPT,我們就知道在START_CKPT之前的所有已經(jīng)commit的事務都不需要再重做了,因此從后 往前掃描日志可以再START_CKPT中記錄的正在進行的事務中最早開始的事務為止。當然,可能通過特定的方式將一個事務的所有日志串接 起來,減少日志的掃描數(shù)量。
?
redo log的簡化實例
redlog在nosql系統(tǒng)中的應用比較廣泛,主要原因是實現(xiàn)簡單。在行級事務的情況下一個事務退化到只有一條日志,這個時候的操作是最簡單的:
此時存在的問題是更新數(shù)據(jù)庫的步驟失敗如何處理?這里有兩種方式:
顯然,第一種處理方式更加優(yōu)美和諧。
這里提到了事務預處理,它是優(yōu)化事務性能很關鍵的技術。由于對事務的操作往往是串行的,如果對數(shù)據(jù)的讀取也按照存心的方式進行處理, 那么這個系統(tǒng)的tps肯定無法提高。簡單的事務預處理就是通過并行的方式讀取數(shù)據(jù),調(diào)高事務前期處理的并發(fā)度, 而真正在進行事務處理的時候除寫日志以外可以做到完全的內(nèi)存操作,以此提高系統(tǒng)的tps。
?
對于這種簡化版的redo log的checkpoint就很簡單了:
在工程實踐中,很多技術點需要簡單可依賴。
?
UNDO/REDO LOG
正如前面所說,undo log的缺點十分明顯:要求事務在完成以后事務所涉及到的所有數(shù)據(jù)庫數(shù)據(jù)都馬上進行持久化,這樣的性能顯然是誰 也無法接受的。redo log在nosql系統(tǒng)中得到了很廣泛的應用,但是在處理復雜事務的時候仍然會有相應的缺點:由于事務在真正的提交 以前,對數(shù)據(jù)的更新都必須啊放在事務局部的緩沖區(qū)里,這樣可能會導致事務占用大量的內(nèi)存。
另外,在解決分布式一致性問題的時候,存在情況確實是需要回滾的,此時redo log就無能為力了。具體的例子參見本站內(nèi)對?chubby一種可能實現(xiàn)的分析。
而undo/redo log可以很好的解決這些問題。undo/redo log是指在日志回放的時候像undo log那樣回滾所有沒有commit的事務; redo log一樣redo所有已經(jīng)commit的事務。由于同時要進行redo和undo,因此日志記錄中必須同時記錄修改前的值和修改后的值。 <T, X, v, w>,表示事務T修改了元素X的內(nèi)容,修改之前X的值為v,修改之后值為w。同時undo/redo log對于數(shù)據(jù)和日志的持久化 順序要求很低:
- URl Before modifying any database element X on disk because of changes made by some transaction T, it is necessary that the update record <T, X, v, w> appear on disk
就是說,在讀數(shù)據(jù)庫進行修改前,必須前必須先寫事務更新日志。undo/redo log也被稱作write ahead log。
日志與數(shù)據(jù)更新的過程:
?
日志回放與checkpoint
沒有checkpoint的日志回放很簡單:首先從后往前遍歷所有日志,undo所有沒有commit的事務,并追加abort,同時記錄所有 已經(jīng)提交的事務;然后從前往后遍歷日志,redo所有已經(jīng)提交的事務。
redo/undo log的checkpoint方式與redo log相似:
與redo log checkpoint的區(qū)別是:在第二步,undo/redo log可以將所有數(shù)據(jù)持久化到磁盤,包括還沒有commit的事務;而 redo log在第二步的時候只能夠?qū)⑺幸呀?jīng)commit的事務的臟數(shù)據(jù)持久化到磁盤。
在《Database Systems: The Complete Book》一書中,關于undo/redo log的checkpoint有一段這樣的描述:
- A transaction must not write any values (even to memory buffers) until it is certain not to abort.
筆者暫時還沒有理解這段描述的意思,歡迎大家探討。我的理解是:因為在生成 checkpoint的第二步,會把所有臟數(shù)據(jù)持久化到磁盤,那么這個時候所有的更新(即使沒有commit的事務的更新)都回被 其他事務看到,如果某個沒有commit的事務最終abort了,這樣其他的事務就看到了不一致的數(shù)據(jù)。 如果我的理解是正確的, 那么undo/redo log和redo log一樣在事務真正提交之前,對數(shù)據(jù)的所有更新都必須在事務局部的緩沖區(qū)里面,那么undo/redo log相對于redo log而言就沒有這方面的優(yōu)勢了。?那么在單機環(huán)境下,undo/redo log相對于redo log還有什么優(yōu)勢呢?
轉(zhuǎn)載于:https://www.cnblogs.com/viviancc/archive/2012/09/15/2686473.html
總結(jié)
- 上一篇: jvm在不同系统中的最大内存空间地址
- 下一篇: linux下×××postfix