天天看點

MySQL啟用Gtid時如何確定Slave crash safe 背景 MySQL參數 測試方法 原因 解決辦法 引申問題 參考 相關代碼

MySQL5.6 支援slave crash safe特性,根據之前對slave crash safe特性的認識,在配置了以下參數的情況下,可以保證slave crash後保證資料的一緻性。

但是,用MySQL5.6(Percona Server 5.6.31) 配置基于GTID的主從複制(MASTER_AUTO_POSITION=1)後,進行slave當機測試時,發現slave恢複後,複制正常但資料不一緻(注意沒有報錯,主備的GTID也是一緻的!!!)。

使用上面的參數搭建主從複制

執行一個腳本,不斷執行下面的insert語句

測試環境是虛機,通過殺Slave虛機程序模拟Slave當機,然後再重新開機Slave虛機并啟動mysql。

重新開機Slave虛機并啟動mysql後,MySQL複制正常,但查詢資料時發現遺漏了一些資料。

正常情況下,max(id)應該和count(*)值相等。

MySQL錯誤日志中有如下消息。

參考官方文檔

http://dev.mysql.com/doc/refman/5.6/en/replication-solutions-unexpected-slave-halt.html

上面官方文檔上寫的 relay_log_recovery=0,是個筆誤,應該是relay_log_recovery=1,我提個了個bug報告(https://bugs.mysql.com/bug.php?id=83711),已經得到了确認。

測試使用的參數是滿足官方文檔的要求的,但沒有起到crash safe的效果。

進一步調查,發現問題的根源是下面2個參數

在使用GTIDs且MASTER_AUTO_POSITION=1的情況下,Slave繼續執行binlog的位置是基于Executed_Gtid_Set的(不是儲存在mysql.slave_relay_log_info中binlog檔案位置),Executed_Gtid_Set是在mysqld啟動時通過掃描binlog擷取的。由于sync_binlog=1,是以binlog裡的位置是最新的,而innodb_flush_log_at_trx_commit = 2并不是每次刷盤,是以innodb的redo log裡會丢失一些資料,即Slave的資料檔案和Executed_Gtid_Set不一緻。這就導緻了重新啟動複制後會丢失部分更新。

另外一個相似的現象是,把innodb的redo log設成同步刷,而binlog異步刷,這會導緻Slave重複回放已經執行過的binglog事件,在這個測試裡的結果就是出現主鍵沖突。

修改下面2個參數為雙1,可以確定資料檔案和binlog檔案一緻。修改後問題不再出現。

即,MySQL5.6啟用GTIDs且MASTER_AUTO_POSITION=1時,可確定slave crash safe的參數設定如下:

每次事務送出都刷binlog和redo log的設定是最安全的,但會對性能一定影響。

在MySQL 5.7裡有另外的解決辦法。MySQL 5.7增加了一個系統表mysql.gtid_executed用于持久化已執行的gtid資訊。即在沒有開啟log_bin或者從伺服器沒有開啟log_slave_updates時每次事務送出往mysql.gtid_executed裡插入一個gtid記錄,這和relay_log_info_repository的處理方式相似。是以不需要把sync_binlog和innodb_flush_log_at_trx_commit設定為1就可以確定gtid_executed和實際的資料檔案一緻。不過在MySQL 5.7開啟log_bin或者從伺服器開啟log_slave_updates時,隻在flush log,伺服器停止等場景下才寫mysql.gtid_executed,Slave crash時依然有gtid_executed和資料檔案不一緻的問題。

後來查閱bug記錄,這是一個已知bug,并且2013年就被發現了。

<a href="http://bugs.mysql.com/bug.php?id=70659">http://bugs.mysql.com/bug.php?id=70659</a>

如果采用基于Position的複制是不是就不需要binlog和redo log都實時刷盤了?

當relayloginfo_repository=TABLE時,Slave執行的位置資訊是和apply event在同一事務裡送出的,是以可以保證它們是一緻的。但基于Position的複制在多線程複制下會有gap和Gap-free low-watermark position的問題,也不能保證資料一緻,需要注意,詳見。

http://dev.mysql.com/doc/refman/5.7/en/replication-features-transaction-inconsistencies.html

http://mysqllover.com/?p=594

https://yq.aliyun.com/articles/41152

https://yq.aliyun.com/articles/50873

http://www.tuicool.com/articles/AV3eqaz

mysqld啟動時從binglog檔案讀取已執行的gtid,從最後一個檔案開始讀。

基于GTID的binlog dump

繼續閱讀