事务日志
轉自:http://nosql-wiki.org/foswiki/bin/view/Main/TransactonLog
?
日志保證了數據的持久性和事務的原子性??梢院唵蔚恼J為日志是一個不斷追加日志記錄的文件。單條日志記錄是一段二進制緩沖區。 下面是本文會使用到的幾條通用的日志記錄:
- 標示trasaction的開始
- 標示transcatoin成功提交,所有對數據的修改都已經成功。由于cache的存在,在日志中看到COMMIT并不一定意味著 數據的修改都已經持久化。日志的目的就是保證所有COMMIT的事務的修改在程序程序異常退出的情況下能夠保留;所有沒有COMMIT 的事務的修改在程序異常退出的情況下都不會保留,就像這些事務根本就沒有START一樣。
- 事務T的所有修改都不能保留下來,最終體現出來的東西就像事務T根本就沒有START過。
日志的類型主要有:undo log,redo log,undo/redo log。最經常使用的類型為redo log和undo/redo log。 如果系統不出現異常情況, 那么日志是沒有必要的,因此在講述的時候大部分場景都是指系統異常退出重啟,在敘述過程中不在重復描述這個場景前提。
?
UNDO LOG
日志內容
undo log就是把所有沒有COMMIT的事務回滾到事務開始之前的狀態,對于已經commit的事務不做任何處理。 因為對于commit的事務不做任何 處理,那么在寫COMMIT日志記錄之前,事務對數據的修改都必須已經持久化, 如果只有一部分持久化,事務修改的數據會處于不一致狀態。 另外,由于需要做undo操作,因此日志記錄中必須包含數據修改前的值, 單條的undo log形式為,表示在事務T開始運行前, X 的值為v;由于對未commit的事務必須進行undo操作,那么在對數據庫的數據進行修改之前,必須先保證事務日志已經持久化, 如果日志沒有持久化,并且最后事務沒有commit,那么數據就無法回滾到事務開始前的狀態。由此可以總結出undo log必須滿足的兩條規則:
- 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
因此,對于日志和數據本身持久化的順序為:
在這里我們可以看到,每個事務commit之前必須把對數據的修改進行持久化,這樣會導致性能問題, 因為每次事務都回帶來一次數據文件的 sync 寫入,而使用日志的主要目的就是減少磁盤的sync操作。 因此undo log存在較大的性能問題,因此在實際中使用并不太多。
?
日志回放
系統重啟回放日志,只需要從后往前掃描日志文件,對于所有沒有commit的事務按照日志記錄中的數據做回滾操作。
?
CheckPoint
按照上述方法回放日志,需要掃描所有日志文件,并且日志文件不能刪除。但是實踐上我們可以看到, 如果一個事務已經commit了那么之前的 日志記錄其實就可以不回放了。因此引入checkpoint的概念。
最簡單的checkpoint做法是在做checkpoint的時候阻塞所有更新,直到所有未決的事務都commit活著abort, 然后記錄。在日志回放的時候, 如果碰到就停止回放日志。阻塞更新當然不是優雅的處理方式。 下面介紹一種不阻塞更新的checkpoint方法。
生成checkpoint的過程為:
日志回放的時候,如果首先遇到END_CKPT,只需要回放日志到下一個START_CKPT為止,START_CKPT之前的日志可以丟棄;如果首先碰到的是START_CKPT, 只需要回放第一步中記錄的所有事務最早開始的地方,再之前的日志記錄可以直接刪除。
?
REDO LOG
redo log是指在回放日志的時候把已經commit的事務重做一遍,對于沒有commit的事務按照abort處理。日志回放并不會處理任何沒有commit的事務, 因此,在COMMIT日志持久化之前,不能將數據的修改持久化。因為如果數據在COMMIT之前持久化,那么在系統異常退出的情況下,這種部分修改的 事務就會處于一種不一致狀態。同時,由于重做事務,因此事務日志中必須記錄事務修改以后的值。redo log必須滿足以下規則:
- 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與數據修改的順序為:
?
日志回放與checkpoint
對于沒有checkpoint的日志回放需要:首先從后往前掃描日志:記錄所有已經commit的事務,對于沒有commit的事務在日志末尾追加abort; 然后從前往后掃描日志,redo所有已經commit的事務日志。
redo log生成checkpoint的方法:
在從后往前掃描日志文件的時候,如果碰到END_CKPT,我們就知道在START_CKPT之前的所有已經commit的事務都不需要再重做了,因此從后 往前掃描日志可以再START_CKPT中記錄的正在進行的事務中最早開始的事務為止。當然,可能通過特定的方式將一個事務的所有日志串接 起來,減少日志的掃描數量。
?
redo log的簡化實例
redlog在nosql系統中的應用比較廣泛,主要原因是實現簡單。在行級事務的情況下一個事務退化到只有一條日志,這個時候的操作是最簡單的:
此時存在的問題是更新數據庫的步驟失敗如何處理?這里有兩種方式:
顯然,第一種處理方式更加優美和諧。
這里提到了事務預處理,它是優化事務性能很關鍵的技術。由于對事務的操作往往是串行的,如果對數據的讀取也按照存心的方式進行處理, 那么這個系統的tps肯定無法提高。簡單的事務預處理就是通過并行的方式讀取數據,調高事務前期處理的并發度, 而真正在進行事務處理的時候除寫日志以外可以做到完全的內存操作,以此提高系統的tps。
?
對于這種簡化版的redo log的checkpoint就很簡單了:
在工程實踐中,很多技術點需要簡單可依賴。
?
UNDO/REDO LOG
正如前面所說,undo log的缺點十分明顯:要求事務在完成以后事務所涉及到的所有數據庫數據都馬上進行持久化,這樣的性能顯然是誰 也無法接受的。redo log在nosql系統中得到了很廣泛的應用,但是在處理復雜事務的時候仍然會有相應的缺點:由于事務在真正的提交 以前,對數據的更新都必須啊放在事務局部的緩沖區里,這樣可能會導致事務占用大量的內存。
另外,在解決分布式一致性問題的時候,存在情況確實是需要回滾的,此時redo log就無能為力了。具體的例子參見本站內對?chubby一種可能實現的分析。
而undo/redo log可以很好的解決這些問題。undo/redo log是指在日志回放的時候像undo log那樣回滾所有沒有commit的事務; redo log一樣redo所有已經commit的事務。由于同時要進行redo和undo,因此日志記錄中必須同時記錄修改前的值和修改后的值。 <T, X, v, w>,表示事務T修改了元素X的內容,修改之前X的值為v,修改之后值為w。同時undo/redo log對于數據和日志的持久化 順序要求很低:
- 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
就是說,在讀數據庫進行修改前,必須前必須先寫事務更新日志。undo/redo log也被稱作write ahead log。
日志與數據更新的過程:
?
日志回放與checkpoint
沒有checkpoint的日志回放很簡單:首先從后往前遍歷所有日志,undo所有沒有commit的事務,并追加abort,同時記錄所有 已經提交的事務;然后從前往后遍歷日志,redo所有已經提交的事務。
redo/undo log的checkpoint方式與redo log相似:
與redo log checkpoint的區別是:在第二步,undo/redo log可以將所有數據持久化到磁盤,包括還沒有commit的事務;而 redo log在第二步的時候只能夠將所有已經commit的事務的臟數據持久化到磁盤。
在《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的第二步,會把所有臟數據持久化到磁盤,那么這個時候所有的更新(即使沒有commit的事務的更新)都回被 其他事務看到,如果某個沒有commit的事務最終abort了,這樣其他的事務就看到了不一致的數據。 如果我的理解是正確的, 那么undo/redo log和redo log一樣在事務真正提交之前,對數據的所有更新都必須在事務局部的緩沖區里面,那么undo/redo log相對于redo log而言就沒有這方面的優勢了。?那么在單機環境下,undo/redo log相對于redo log還有什么優勢呢?
轉載于:https://www.cnblogs.com/viviancc/archive/2012/09/15/2686473.html
總結
- 上一篇: jvm在不同系统中的最大内存空间地址
- 下一篇: How to Review a Pape