通過報錯信息可知,worker 線程在回放事務 '471c2974-f9bb-11eb-afb1-52540010fb89:88313207' 時,由於要插入的記錄主鍵沖突報錯。
主機重啟前,主從同步正常,主機重啟後,主從同步由於主鍵沖突報錯,對比了沖突主鍵所在行記
錄在主從庫是壹致的,初步分析事務 '471c2974-f9bb-11eb-afb1-52540010fb89:88313207' 在主機故
障前已經在從庫進行了回放,那為何事務會重復回放呢?
在開啟gtid模式下,如果指定 master_auto_position=1,start slave 時,從庫會把
Retrieved_Gtid_Set 和 Executed_Gtid_Set 的並集發送給主庫,主庫將收到的並集和自己的
gtid_executed 比較,把從庫 gtid 集合裏缺失的事務全都發送給從庫。
主機重啟後,事務重復回放,表明 Retrieved_Gtid_Set 和 Executed_Gtid_Set 的並集中有 GTID 事務
丟失,導致重復獲取事務執行引發主鍵沖突錯誤。Retrieved_Gtid_Set 和 Executed_Gtid_Set 均為內存變
量,MySQL 重啟後,Retrieved_Gtid_Set 初始化為空值,從而推斷出 Executed_Gtid_Set 有 GTID 事務丟
失。
Executed_Gtid_Set 來源於 gtid_executed 變量,gtid_executed 變量持久化介質有
mysql.gtid_executed 表和 binlog ,其中 mysql.gtid_executed 表是 MySQL 5.7 後引入的,在 MySQL 5.6 中,從庫要使用 GTID ,必須要先設置 log_bin=on,log_slave_updates=on ,因為從庫執行過的 GTID 只保留在 binlog 中。
gtid_executed 變量值陳舊,推斷出 binlog 未實時持久化,我們看壹下參數 sync_binlog :
通過以上分析,此次故障來龍去脈就清楚了:
Worker 線程報 1062 主鍵沖突錯誤 --> gtid_executed 信息陳舊 --> binlog 未實時持久化
搭建壹主壹從測試環境,通過 sysbench 模擬主庫並發插入,從庫主機暴力關機後,故障復現:
既然錯誤原因是事務重復執行,那跳過錯誤就好了,有如下兩種方式,根據需要選取其中壹種方式執行:
如果最新 binglog 丟失的 GTID 較多,手工執行比較繁瑣,需要不斷試錯。可寫壹個存儲過程批量執行:
待主從同步正常後,再取消參數 slave_skip_errors 設置重啟 MySQL 。