上週在生產環境遭遇一個棘手問題,經排查後發現是 MySQL 多線程復制(MTS)機制導致的 Error 1872 錯誤,特此記錄分享給各位 DBA 同仁參考。
因 IDC 機房突發斷電(疑似挖掘機誤切光纜),導致所有伺服器重啟,其中 MySQL 5.7.10 從庫復制中斷,報錯如下:
Slave SQL for channel "": Slave failed to initialize relay log info structure from the repository, Error_code: 1872
雖然採用了標準 Crash-safe 配置(relay_log_info_repository=TABLE、master_info_repository=TABLE、sync_relay_log=1、sync_relay_log_info=1),但在多線程復制(MTS)場景下,仍存在兩大固有問題:
MTS 下,後執行的事務可能先回放提交。如圖所示,事務 tx2、tx4 已提交,但 tx1、tx3 尚未提交,形成「空洞」。基於 logical_clock 的 MTS 可透過設定 slave_preserve_commit_order=1 保證提交順序,但這並不能完全解決位置追蹤問題。

Crash 發生時,master_info 記錄的是最早未提交事務(如 tx1)的起始位置,而非實際已提交的最新位置。這被稱為 gap-free low-watermark。關鍵在於:MTS 下 slave_relay_log_info 表的更新非事務性,導致位置資訊與實際回放進度脫節。
MySQL 5.6 引入 slave_worker_info 表,記錄每個 Worker 線程的回放位置,且該表更新是事務性的。恢復時,MySQL 會對比 Exec_Master_Log_Pos 與各 Worker 的 Master_log_pos,判斷是否需重放事務。
Crash 後必須手動執行以下指令修復 Gap,直接執行 CHANGE MASTER TO 會觸發 1872 錯誤:
START SLAVE UNTIL SQL_AFTER_MTS_GAPS;
START SLAVE SQL_THREAD;
MySQL 內建自動修復機制,Crash 後能自動準確恢復復制狀態,無需人工干預。
生產環境為 MySQL 5.7.10,DBA 嘗試用 CHANGE MASTER TO 修復,導致 1872 錯誤。正確做法應先執行 START SLAVE UNTIL SQL_AFTER_MTS_GAPS 清理 Gap,再啟動 SQL 線程。後續升級至 5.7.15 過程中又遇新坑,留待下回分享。
核心提醒:MTS 環境下 Crash 後,切勿直接 CHANGE MASTER TO,務必先處理 Gap 事務。