MySQL:binlog 和 redo log


【參考文章】:MySQL中Redo與Binlog順序一致性問題?

【參考文章】:極客時間

1. 數據更新時的日志處理流程

  

1.1 redo log(prepare狀態)

  此時SQL已經成功執行了,已經產生了語句的redo和undo內存日志,已經進入了事務commit步驟。然后告訴引擎做Prepare完成第一階段,Prepare階段就是寫Prepare Log(Prepare Log也是Redo Log),將事務狀態設為TRX_PREPARED,寫Prepare XID(事務ID號)到Redo Log。寫XID到Redo Log的時候會一並把Redo Log刷新到磁盤,這個時候Redo Log的日志量大小取決於執行SQL語句時產生的Redo是否被刷盤,這個刷盤是隨機的,后台Master線程每秒鍾都會刷新一次。

1.2 binlog

  如果事務涉及的所有存儲引擎的Prepare(即Redo Log寫入磁盤之后)都執行成功,則調用TC_LOG_BINLOG::log_xid方法將SQL語句寫到Binlog(write()將binary log內存日志數據寫入文件系統緩存,fsync()將binary log文件系統緩存日志數據永久寫入磁盤),同時也會把XID寫入到Binlog。此時,事務已經鐵定要提交了。否則,調用ha_rollback_trans方法回滾事務,而SQL語句實際上也不會寫到binlog。

  Binlog是事務commit時才刷新到磁盤,如果binlog太大則commit時會慢

1.3 redo log(commit狀態)

  最后,調用引擎的Commit完成事務的提交。並且會對事務的undo log從prepare狀態設置為提交狀態(可清理狀態),刷新Commit Log到Redo Log,釋放鎖,釋放mvcc相關的read view等等;將事務設為TRX_NOT_STARTED狀態。

1.4 兩階段提交

  由上面的二階段提交流程可以看出,通過兩階段提交方式保證了無論在任何情況下,事務要么同時存在於存儲引擎和binlog中,要么兩個里面都不存在,可以保證事務的binlog和redo log順序一致性。一旦階段2中持久化Binlog完成,就確保了事務的提交。

  此外需要注意的是,每個階段都需要進行一次fsync操作才能保證上下兩層數據的一致性。

  階段1的fsync由參數innodb_flush_log_at_trx_commit=1控制,階段2的fsync由參數sync_binlog=1控制,俗稱“雙1”,是保證CrashSafe的根本。

1.5 CrashSafe

  CrashSafe指MySQL服務器宕機重啟后,能夠保證:

  – 所有已經提交的事務的數據仍然存在。

  – 所有沒有提交的事務的數據自動回滾。

2. binlog

  二進制日志是server層的,主要用來做主從復制和即時點恢復時使用的。

2.1 日志記錄的三種模式

  基於SQL語句的復制(statement-based replication,SBR):記錄執行的SQL語句

  基於行的復制(row-based replication,RBR):記錄更新的每一條記錄的變化情況

  混合模式復制(mixed-based replication,MBR):根據具體的更新語句選擇上述兩種中的一種方式記錄

2.2 設置 binlog 日志模式 

  靜態設置,配置文件形式 

vi my.cnf

    binlog_format="STATEMENT"

  動態設置,命令形式

 mysql> SET GLOBAL binlog_format = 'STATEMENT';

3. redo log

  事務日志(redo log)是InnoDB存儲引擎層的,用來保證事務安全的。

3.1 redo log 文件

  redo log 是固定大小的,從頭開始寫,寫到末尾又回到開頭循環寫;

  redo log 有兩個指針:

  一個為 write pos:表示當前記錄的位置,一邊寫一邊后移;

  一個為 checkpoint:表示當前要擦除的位置,一邊擦除一邊后移,擦除之前要將記錄寫到磁盤文件中;

4. 區別

  binlog 屬於MySQL的 sever 層,所有引擎都可以使用;redo log 屬於 InnoDB引擎特有。

  binlog 是邏輯日志,記錄的是SQL語句的原始邏輯;redo log 是物理日志,記錄的是在某個數據頁上做了什么修改。

  binlog 是追加寫,一個文件寫滿之后就寫到下一個文件,不會覆蓋之前的文件;redo log 是循環寫,寫到文件末尾之后又從文件起始位置開始寫,會覆蓋之前的日志。

5. 故障恢復

  開啟Binary log的MySQL在crash recovery時:MySQL在prepare階段會生成xid,然后會在commit階段寫入到binlog中。在進行恢復時事務要提交還是回滾,是由Binlog來決定的

  – 事務的Xid_log_event存在,就要提交。

  – 事務的Xid_log_event不存在,就要回滾。

恢復的過程非常簡單:

  – 掃描最后一個Binlog文件(進行rotate binlog文件時,確保老的binlog文件對應的事務已經提交),提取其中的Xid_log_event

  – 重做檢查點以后的redo日志,讀取事務的undo段信息,搜集處於prepare階段的事務鏈表,將事務的xid與binlog中的xid對比,若存在,則提交,否則就回滾

總結一下,基本頂多會出現下面是幾種情況:

  • 當事務在prepare階段crash,數據庫recovery的時候該事務未寫入Binary log並且存儲引擎未提交,將該事務rollback。
  • 當事務在binlog階段crash,此時日志還沒有成功寫入到磁盤中,啟動時會rollback此事務。
  • 當事務在binlog日志已經fsync()到磁盤后crash,但是InnoDB沒有來得及commit,此時MySQL數據庫recovery的時候將會讀出二進制日志的Xid_log_event,然后告訴InnoDB提交這些XID的事務,InnoDB提交完這些事務后會回滾其它的事務,使存儲引擎和二進制日志始終保持一致。

  總結起來說就是如果一個事務在prepare階段中落盤成功,並在MySQL Server層中的binlog也寫入成功,那這個事務必定commit成功。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM