MySQL的undo/redo日誌和binlog日誌,以及2PC

發現本身的知識點有點散,今天就把它們鏈接起來,好好總結一下。html

 

1、undo log、redo log、binlog的定義和對比

  定義和做用                       所在架構層級 日誌形式 所在文件和默認名稱,組織結構 是否緩存,如何緩存  寫文件方式
undo log

回滾日誌,在事務執行的過程當中操做任何數據以前先將數據備份到undolog中。mysql

事務失敗時可根據undo log進行回滾。sql

用來保證事務的一致性。數據庫

還能夠用來實現多版本併發控制MVCC。緩存

InnoDB引擎層 邏輯日誌,以行的形式進行記錄。

共享表空間文件,ibdata0/ibdata1。架構

undo只是該文件的的一部分(rollback segment),文件由頁組成,每一頁又由一行行的數據組成,undo相對有本身的固定頁,會循環覆蓋。併發

Rollback segment,一共有128個,分別從resg slot0 - resg slot127,每個resg slot,也就是每個回滾段,內部由1024個undo segment組成。分佈式

是,innodb_buffer_pool緩衝池中有undo頁

儘可能順序寫。 post

回滾,實際作的是與以前相反的工做,好比INSERT須要的是DELETE,而DELETE須要的是INSERT。url

執行相反的UPDATE,將修改前的行放回去。

回滾操做寫入磁盤時爲隨機寫。

redo log

重作日誌,在事務執行的過程當中不斷記錄事務操做的變化。

恢復提交後的物理數據頁(恢復數據頁,且只能恢復到最後一次提交的位置)。

用來保證事務的原子性和持久性。

InnoDB引擎層 物理日誌,記錄的是數據頁的物理修改。

重作日誌文件,ib_logfile0/ib_logfile1。

有本身的頁結構,會循環覆蓋。

是,專門的獨立的redo緩衝區

儘可能順序寫。

先寫入日誌緩衝中,而後按照必定的條件順序寫入redo日誌文件。

恢復操做寫入磁盤時爲隨機寫。

 

 
binlog

二進制日誌,在事務提交後進行記錄。

用來備份, 經過主從複製來實現數據同步和讀寫分離。

MySQL數據庫(上)層 邏輯日誌,記錄數據庫全部增刪改操做(sql語句)。

二進制日誌文件,localhost-bin.000001~localhost-bin.00000n。

有本身的文件格式和文件結構,不會循環覆蓋,追加寫,文件寫滿再新建。

是,每一個會話有一個默認32K的緩衝。 順序寫。 

 

 2、undo log與redo log的總結和補充

Undo 記錄某數據被修改的值,能夠用來在事務失敗時進行rollback;重要的是,undo log會產生redo log,也就是undo log的產生也會伴隨redo log的產生,這是由於undo log也須要持久性的保護。即undo也是數據頁的一部分。

Redo 記錄某數據塊被修改的值,能夠用來恢復未寫入data file 的已成功事務更新的數據。即redo log是對數據頁修改後刷髒的一個有力補充。即WAL技術,Write-Ahead Logging,先寫日誌文件,再寫到數據庫頁緩存,最後刷到磁盤的數據庫中。

例如某一事務的事務序號爲T1,其對數據X進行修改,設X的原值是5,修改後的值爲15,那麼Undo日誌爲<T1, X, 5>,Redo日誌爲<T1, X, 15>。

 

3、redo log和binlog,以及2PC

redo log是在事務進行中不斷被寫入,因此每一個事務對應多個日誌條目。

binlog 是在事務提交完成後,進行一次寫入。因此對於每一個事務僅僅對應一個日誌記錄。

 

redo log日誌刷盤機制和參數innodb_flush_log_at_trx_commit有關。

binlog 何時刷新到磁盤跟參數sync_binlog有關。 

innodb_flush_log_at_trx_commit

0: 每隔1s,由系統後臺線程刷log buffer,也就是把redo日誌刷盤,這裏會調用fsync,因此可能丟失最後1s的事務。

1: 每次commit時,刷redo日誌,肯定fsync刷盤。爲默認值。

2: 每次提交時,刷redo日誌到文件系統,不調用fsync刷盤,5.6.6以前是每隔1s刷盤,以後的版本是經過參數innodb_flush_log_at_timeout設置,默認也是1s。因此也可能丟最後一秒的事務。若是有掉電保護組件的話,能夠開啓。

sync_binlog

表示每多少個sync事件觸發一次真正的binlog fsync刷盤,默認是1,表示每次commit時binlog都會fsync。

建議這兩個參數都設置成1.

  

內部XA事務與2PC

InnoDB存儲引擎提供了對XA事務的支持,並經過XA事務來支持分佈式事務的實現。

分佈式事務(Distributed Transactions)指的是容許多個獨立的事務資源(transactional resources)參與到一個全局的事務中。全局事務也必須遵循ACID原則。

XA事務容許不一樣數據庫之間的分佈式事務,例如一臺MySQL數據,一臺Oracle數據庫,只要全局事務中的每一個節點都支持XA事務便可。此時,InnoDB的隔離級別必須是SERIALIZABLE。

分佈式事務採用兩階段提交(two-phase commit)的方式。

在第一階段,全部參與全局事務的節點開始準備(PREPARE),告訴事務管理器它們準備好提交了。

在第二階段,事務管理器告訴資源管理器執行ROLLBACK仍是COMMIT。若是任何一個節點顯示不能提交,則全部節點被告知須要回滾。

因此,與本地事務對比,分佈式事務多了一次PREPARE操做,待收到全部節點的贊成信息後,再進行提交或者回滾操做。

 

以上討論的是外部事務,即資源管理器是MySQL數據庫自己。而在MySQL數據庫內部也能夠存在這樣相似的分佈式事務。

資源管理器能夠是存儲引擎或插件,因此能夠是存儲引擎和插件之間,或者存儲引擎與存儲引擎之間,這種被稱爲內部XA事務

最爲常見的內部XA事務存在於binlog與InnoDB存儲引擎之間

既然是XA事務,必然涉及到兩階段提交,對於內部XA而言,一樣存在着提交的兩個階段。

 

這個兩階段提交是在開啓binlog以後,redo與binlog的兩階段提交。

在更新一條數據時,會先執行,而後寫入redo log中,redo log進入prepare狀態,執行器執行完成。

而後執行器生成這個操做的binlog,並寫入磁盤。

而後提交commit,更新完成。

 

假設在任何狀況下(機器掉電)mysqld crash或者os crash,MySQL仍然能保證數據庫的一致性。數據的一致性是如何作到的哪?正是二階段提交。

咱們結合幾種場景來分析下二階段提交是如何作到的:

1.prepare階段,redo log落盤前,mysqld crash

2.prepare階段,redo log落盤後,binlog落盤前,mysqld crash

3.commit階段,binlog落盤後,mysqld crash

對於第一種狀況,因爲redo沒有落盤,毫無疑問,事務的更新確定沒有寫入磁盤,數據庫的一致性不受影響;

對於第二種狀況,這時候redo log寫入完成,但binlog還未寫入,是提交仍是回滾呢?

對於第三種狀況,此時,redo log和binlog都已經落盤,只是undo狀態沒有更新,雖然redo log和binlog已經一致了,事務是否應該提交?

 

對於第三種狀況,咱們能夠蒐集到未提交事務的binlog event,因此須要提交

對於第二種狀況,因爲binlog未寫入,須要經過執行回滾操做來保證數據庫的一致性。

簡而言之,對於異常的XA事務,若binlog已落盤,則事務應該提交;binlog未落盤,則事務就應該回滾。

 

注:以上XA事務的2PC流程主要參考第二篇,和書上稍微有些差異,書上寫的是先提交binlog,我以爲可能更合理。可是不影響對事務2PC的總體理解。 

 

 

參考資料:

《MySQL技術內幕InnoDB存儲引擎》

相關文章
相關標籤/搜索