MySQL 5.6 引入全局事務 ID (GTID) 不僅簡化了故障切換,更引入了全新的**複制協議**。本文對比新舊協議差異,揭示為何 sql_slave_skip_counter 失效、錯誤事務 (Erroneous Transaction) 會導致嚴重後果,並給出正確處理姿勢。
| 維度 | 舊協議 (檔案+位置) | 新協議 (GTID 集合) |
|---|---|---|
| 同步起點 | MASTER_LOG_FILE + MASTER_LOG_POS | 從庫發送 已執行 GTID 集合 |
| 主庫動作 | 從指定位置順序發送事務 | 計算差集,**發送從庫缺失的每個 GTID 事務** |
| 冪等性 | 無保證,重複執行風險 | **嚴格保證**:每個 GTID 在從庫**只執行一次** |
sql_slave_skip_counter 廢用?舊協議下,SET GLOBAL sql_slave_skip_counter = 1 讓 SQL 線程跳過下一個事務。但在 GTID 協議下:
正解:注入空事務佔位
SET GTID_NEXT = 'aaa-bbb-ccc:5'; -- 要跳過的 GTID
BEGIN; COMMIT; -- 空事務
SET GTID_NEXT = 'AUTOMATIC'; -- 恢復自動分配
此法讓 GTID 集合完整,新主庫不再重發,複制鏈路穩定。
若從庫直接執行寫入 (如手動 CREATE DATABASE),產生本地 GTID (錯誤事務)。後續將該從庫提升為主庫,或掛載到新主庫下:
Error 1007: Database exists) 或找不到 Binlog 報 1236,**複制直接中斷**。# 案例 1:主庫用 IF NOT EXISTS 避開衝突,但從庫無此保護
S1: CREATE DATABASE mydb; -- 產生 GTID 100
M: CREATE DATABASE IF NOT EXISTS mydb; -- 不產生新 GTID (或產生不同 GTID)
S2 -> S1: 複制衝突,報 1007
# 案例 2:錯誤事務 Binlog 被清理
S1: CREATE DATABASE mydb; FLUSH LOGS; PURGE BINARY LOGS TO 'bin.000008'; -- GTID 100 被刪
M: CREATE DATABASE IF NOT EXISTS mydb;
S2 -> S1: 缺少 GTID 100 且主庫無 Binlog,報 1236 致命錯誤
read_only=ON、super_read_only=ON)。SET SESSION SQL_LOG_BIN = 0;
-- 執行 DDL/DML
SET SESSION SQL_LOG_BIN = 1;
SHOW MASTER STATUS 與 SHOW SLAVE STATUS 的 Executed_Gtid_Set。結語: GTID 新協議以「嚴格冪等」換取運維簡易,代價是**零容忍錯誤事務與手動跳過**。理解協議本質,才能駕馭 GTID 強大威力而不踩坑。