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

MySQL 半同步複制源碼級實現解析:Master ACK 接收、事務提交流程與 Slave 回應機制

     編輯:MySQL 綜合教學

MySQL 半同步複制源碼級實現解析:Master ACK 接收、事務提交流程與 Slave 回應機制

基於官方 MySQL 5.7 源碼(GitHub),深度剖析 Semi-sync 核心路徑:Master 三大執行緒協作、組提交四階段插入 Semi-sync 等待、Slave IO 執行緒回應邏輯。

一、啟用正確姿勢

# Master
SET GLOBAL rpl_semi_sync_master_enabled=1;
SET GLOBAL rpl_semi_sync_master_timeout=10000;  -- 毫秒

# Slave
STOP SLAVE IO_THREAD;
SET GLOBAL rpl_semi_sync_slave_enabled=1;
START SLAVE IO_THREAD;  -- 必須重啟 IO_THREAD 使參數生效

啟用後觀察 SHOW STATUS LIKE 'Rpl_semi_sync_master_status',ON 表示半同步生效。若因延遲超時會自動降級為 OFF。

調試利器:rpl_semi_sync_master_trace_level / rpl_semi_sync_slave_trace_level(建議 80=64+16,記錄詳細流程與函數調用)。

二、Master 端三大核心執行緒

  1. Binlog Dump 執行緒:每個 Slave 一條,負責讀取 Binlog 發送給 Slave IO 執行緒
  2. Worker 執行緒:處理客戶端事務提交的工作執行緒
  3. ACK Receiver 執行緒:專責監聽 Slave ACK 封包,通知 Worker 繼續

三、Binlog Dump 流程

核心函數 mysql_binlog_send():

  1. 判斷 Slave 是否 Semi-slave(檢查 Session 變數 rpl_semi_sync_slave),是則 add_slave() 加入 ACK Receiver 監聽隊列
  2. 根據 Slave 請求的 file/pos 讀取 Binlog 事件
  3. updateSyncHeader():根據實時 Semi-sync 狀態決定是否在封包頭打標
  4. my_net_write() + net_flush() 發送
  5. 無新 Binlog 時 wait_for_update_bin_log() 等待

四、半同步事務提交流程(組提交四階段 + Semi-sync 階段)

MySQL 5.6+ 採用組提交,原有 Flush/Sync/Commit 三階段,引入 Semi-sync 後擴展為四階段:

  1. Flush 階段:隊列序列化寫入 Binlog Cache → flush_cache_to_file() 一次 write。若 sync_binlog!=1,此處通知 Dump 執行緒有新 Binlog;若 =1 則等 Sync 階段後再通知(保證主庫 Binlog 先落地)。
  2. Sync 階段:sync_binlog_file() 強制 fsync(視 sync_binlog 值)。
  3. Semi-sync 階段:call_after_sync() → cond_timedwait(&COND_binlog_send) 等待 ACK。
  4. Commit 階段:InnoDB Commit → waitAfterCommit() 再次 cond_timedwait 等待 ACK。

關鍵決策點:由參數 rpl_semi_sync_master_wait_point 決定在階段 3 (AFTER_SYNC) 或階段 4 (AFTER_COMMIT) 等待。AFTER_COMMIT 更安全(主庫已提交),AFTER_SYNC 效能略好。

五、ACK Receiver 執行緒流程

啟動條件:rpl_semi_sync_master_enabled=1。關閉參數則執行緒退出。

  1. 遍歷 Semi-slave 陣列
  2. select() 監聽每個 Slave Socket 可讀事件
  3. my_net_read() 讀取 ACK 封包
  4. reportReplyPacket() 處理狀態:若 Slave 已收到最新 Binlog 位點 → mysql_cond_broadcast(&COND_binlog_send) 喚醒等待的 Worker
  5. 根據運行狀態在 Semi-sync/Async 間切換

六、Slave 端 IO 執行緒流程

核心函數 handle_slave_io():

  1. safe_connect() 建立與 Master 連線
  2. request_dump():
    • 執行 SET @rpl_semi_sync_slave=1 標記自己為 Semi-slave
    • 發送 COM_BINLOG_DUMP 請求 Binlog
  3. 循環接收處理:
    • read_event() 讀取事件(無資料阻塞等待)
    • slaveReadSyncHeader() 解析封包頭 Semi-sync 標記
    • queue_event() 寫入 Relay Log(過濾自生成 Server-ID 事件)
    • 若有 Semi-sync 標記 → slaveReply() 發送 ACK(含當前 Relay Log file/pos)

七、關鍵數據結構

  • ReplSemiSyncMaster:Master 端狀態機,含 m_slaves(Slave 連線陣列)、m_semi_sync_slaves 計數、cond 條件變數
  • ReplSemiSyncSlave:Slave 端狀態,含 net 網路結構、reply ACK 封包緩衝
  • COND_binlog_send:條件變數,Worker 與 ACK Receiver 同步核心

八、總結

Semi-sync 在不改變複制基礎架構前提下,透過 ACK Receiver 執行緒 + 條件變數同步 實現「至少一從庫收到 Binlog」的強一致性保證。核心複雜度在於組提交管道中插入等待點、以及 select() 的擴展性瓶頸(見排查實戰篇)。源碼閱讀建議從 rpl_semi_sync_master.cc、rpl_semi_sync_slave.cc 入手。

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