首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL Binlog 組提交與 XA 兩階段提交原理詳解

     編輯:MySQL 綜合教學

一、XA 兩階段提交(2PC)核心原理

XA 是 X/Open 組織定義的分布式事務規範,定義了事務管理器(TM)與資源管理器(RM)的接口。通過兩階段提交實現多資源的原子性:

1.1 Prepare 階段

  • TM 向所有 RM 發送 prepare 請求
  • RM 執行數據修改、寫日志,將事務狀態置為「可提交」,返回結果
  • 若任一 RM 失敗或超時,TM 判定事務失敗

1.2 Commit 階段

  • 若所有 RM Prepare 成功,TM 發送 commit,RM 將狀態改為「提交完成」
  • 若有 RM Prepare 失敗,TM 發送 rollback,所有 RM 回滾
  • RM 若收不到第二階段指令,超時後自動回滾「可提交」事務

二、MySQL 中的 XA 實現:外部 XA 與內部 XA

MySQL 官方文檔明確:僅 InnoDB 支持 XA,且分布式事務必須使用 SERIALIZABLE 隔離級別(非分布式事務 REPEATABLE READ 即可)。

2.1 外部 XA

  • MySQL Server 作為 RM,客戶端程序作為 TM
  • 跨多個 MySQL 實例/數據庫的分布式事務
  • SQL 語法:XA START 'xid'、XA END 'xid'、XA PREPARE 'xid'、XA COMMIT/ROLLBACK 'xid'

2.2 內部 XA(本文重點)

  • 單個 MySQL 實例內部:Server 層作 TM,存儲引擎作 RM
  • 解決 Binlog(Server 層)與 Redo Log(引擎層)的一致性
  • 跨引擎事務(如 InnoDB + MyISAM)需內部 XA,目前僅 InnoDB 支持表處理器級兩階段提交

三、內部 XA 解決 Binlog 與 Redo Log 一致性

3.1 問題背景

MySQL 4.x 放棄 redo log 復制,引入 binlog 兼容非事務引擎。但引入 binlog 導致新問題:事務提交需同時寫 redo log 和 binlog,誰為準?如何協調?崩潰如何恢復?

3.2 MySQL 5.6 前的兩階段提交實現

Phase 1 (Prepare):
  InnoDB prepare -> 持有 prepare_commit_mutex -> write/sync redo log
  設置回滾段為 Prepared 狀態,binlog 不動作

Phase 2 (Commit):
  1. write/sync Binlog
  2. InnoDB commit (寫 COMMIT 標記,釋放 prepare_commit_mutex)

關鍵點:以 binlog 寫入成敗 作為事務提交成功與否標準。崩潰恢復邏輯:

  1. 掃描最後 binlog 文件提取 XID
  2. InnoDB 維護 Prepared 事務鏈表,比對 XID:
    • Binlog 有 XID → 提交
    • Binlog 無 XID → 回滾

缺陷:sync_binlog=1 時,Phase 2 串行化,持有全局大鎖 prepare_commit_mutex,性能急劇下降。

四、Binlog 組提交優化演進

4.1 MySQL 5.6:三階段並行組提交

將 Phase 2 拆分為三個階段,各階段由一個線程串行處理,但階段間可並行:

  1. Flush 階段:將各線程 binlog 從 cache 寫入文件
  2. Sync 階段:對 binlog 執行 fsync(多線程合併寫入磁盤,核心優化)
  3. Commit 階段:引擎層提交事務(此時 redo log 已在 prepare 階段寫入)

優勢:三階段流水線並行,大幅提升吞吐。Prepare 階段未變(仍 write/sync redo log)。

延伸:5.7 引入 MTS(多線程 Slave 復制),利用組提交時的 seqno 實現從庫並行回放。

4.2 MySQL 5.7 / Percona / AliSQL:Redo Log 組寫入優化

淘寶優化邏輯(官方 5.7.6 合入):

Step 1. InnoDB Prepare,記錄當前 LSN 到 THD
Step 2. 進入 Flush 階段,Leader 收集隊列,計算最大 LSN
Step 3. 將 InnoDB redo log write/fsync 到指定 LSN(隱式 redo log 組寫入)
Step 4. 寫 Binlog 及後續工作 (sync Binlog, InnoDB commit)

核心思想:將 redo log write/sync 延遲到 Binlog 組提交的 Flush 階段之後、Sync Binlog 之前。顯式實現 redo log 組寫入,減少 log_sys->mutex 競爭。Binlog 與 Redo Log 雙雙組提交優化。

官方 Release Note:When using InnoDB with binary logging enabled, concurrent transactions written in the InnoDB redo log are now grouped together before synchronizing to disk when innodb_flush_log_at_trx_commit is set to 1, which reduces the amount of synchronization operations. This can lead to improved performance.

五、關鍵參數:innodb_support_xa

Command-Line Format: --innodb_support_xa
Scope: Global, Session
Dynamic: Yes
Type: Boolean
Default: TRUE
  • 作用:啟用 InnoDB 兩階段提交支持,Prepare 階段額外一次磁盤 flush
  • 必須開啟場景:開啟 log_bin 且多線程並發寫入
  • 關閉後果:binlog 寫入順序與實際提交順序不一致,導致崩潰恢復與從庫回放數據錯誤
  • 可關閉場景:單線程寫入(如從庫僅 SQL 線程回放)、不需 binlog/復制、無外部 XA 管理器

生產建議:主庫永不關閉;從庫若為只讀單線程回放可關閉提升性能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved