binlog
和redo log
區別
為了滿足Mysql的事物ACID特性,InnoDB引入了redo log
和 undo log
日志文件。為了滿足主從同步Mysql引入了binlog
日志文件。redo log
和binlog
文件都保存的數據庫對數據庫的修改,但是binlog
和redo log
本質上是不一樣的:
redo log
是存儲引擎層產生,僅支持Innodb;binlog
是mysql數據上層產生,支持所有存儲引擎。redo log
是記錄物理日志,記錄的是頁的物理修改;binlog
記錄的是邏輯日志,記錄的是SQL語句。redo log
是在事務進過程中產生,日志內容并不是隨著事務提交順序寫入;binlog
是在事務提交完成后釋放鎖之前進行一次性的寫入。redo log
主要所用是保證事務持久性;binlog
主要用來所恢復和復制。
為什么需要二階段提交(2PC)
當redo log
和binlog
數據不一致時就可能導致主從數據不一致,比如:
- 只保存了
redo log
日志,當主節點宕機重啟后,主節點可以通過redo log
日志恢復事物,保存數據最新,但是binlog
丟失無法完成主從同步,這樣就導致從節點沒有最新數據。 - 只保存了
binlog
,當主節點宕機重啟后,本機最新事物無法重新執行,數據丟失,但是從庫可能通過binlog
已經收到了修改通知,從庫將會存在最新數據,而主庫沒有。
為了避免這種情況,MySQL 引入了兩階段提交的機制。
兩階段提交就是將一個事務分成兩個階段來提交:prepare 階段和 commit 階段。在 prepare 階段,事務會先寫 redo log 并將其標記為 prepare 狀態,然后寫 binlog;在 commit 階段,事務會將 redo log 標記為 commit 狀態,并將 binlog 落盤。這樣,無論數據庫在哪個時刻發生宕機,都可以根據 redo log 和 binlog 的狀態來判斷事務是否提交,并保證數據的一致性。
兩階段提交的流程
MySQL采用了如下的二階段提交流程:
- 在準備階段,MySQL先將數據修改寫入redo log,并將其標記為prepare狀態,表示事務還未提交。然后將對應的SQL語句寫入bin log。
- 在提交階段,MySQL將redo log標記為commit狀態,表示事務已經提交。然后根據sync_binlog參數的設置,決定是否將bin log刷入磁盤。
通過2PC
機制,MySQL可以保證在任何時刻,redo log和bin log都是邏輯上一致的。如果MySQL發生崩潰,可以根據redo log
恢復數據頁的狀態,也可以根據bin log
恢復SQL語句的執行。