MySQL 主從複製,常見的binlog錯誤及解決方法

wuchangsoft發表於2024-07-30

在主從複製架構下,MySQL透過binlog來實現主從資料的一致性。

MySQL主從複製主要有以下步驟

1. master將改變記錄到binary log

2. slave io_thread去請求主庫的binlog,並將得到的binlog日誌寫到relay log

3. slave sql_thread重做relay log中的事件

除了作為MySQL主從複製的紐帶,binlog還有其他的作用。比如:

1. 透過mysqlbinlog工具解析binlog檔案,來進行Point-in-Time資料庫恢復;

2. 基於binlog事件,進行資料庫的flashback(閃回)(mariadb可以直接使用mysqlbinlog進行flashback)

3. Github開源的線上改表工具gh-ost也是透過binlog來實現的

4. 還可以透過解析binlog進行增量訂閱&消費

binlog如此有用,但是在平日的運維過程中難免遇到一些問題。下面介紹幾種binlog相關的錯誤。

常見問題之一

現象: mysqlbinlog5.5解析mysql5.7 binlog檔案出現

ERROR: Error in Log_event::read_log_event(): 'Sanity check failed', data_len: 31, event_type: 35

ERROR: Could not read entry at offset 123: Error in log format or read error.

原因分析

** mysql5.6等高版本binlog檔案增加了新的binlog event,如gtid event等。

** mysql5.5版本的mysqlbinlog是識別不了這樣的binlog event的。

解決方法:使用高版本的mysqlbinlog解析低版本的mysql產生的binlog

常見問題之二

現象:正常執行的mysql伺服器show slave status出現

Last_SQL_Error:Relay log read failure: Could not parse relay log event entry.

The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log),

the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log),

a network problem, or a bug in the master's or slave's MySQL code.

If you want to check the master's binary log or slave's relay log,

you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.

原因分析:無法讀取relay log 裡的條目,可能因為master庫的binlog錯誤,或slave庫的中繼日誌錯誤,或者網路問題及bug原因。一般是由於網路故障或slave庫壓力過大,導致relay-log格式錯誤造成的。

解決方法:

找到當前已經同步的時間點,重新設定主從同步後,就會產生新的中繼日誌,恢復正常。

"show slave status\G"的輸出中,找到如下資訊:

Relay_Master_Log_File: mysql-bin.002540 //slave庫已讀取的masterbinlog

Exec_Master_Log_Pos: 950583017 //slave上已經執行的position位置點

停掉slave,以slave已經讀取的binlog檔案,和已經執行的position為起點,重新設定同步。

Relay_Master_Log_File: mysql-bin.002540 //slave庫已讀取的masterbinlog

Exec_Master_Log_Pos: 950583017 //slave上已經執行的position位置點

常見問題之三

現象:當機之後恢復show slave status報錯:

Last_SQL_Error: Error initializing relay log position: I/O error reading the header from the binary log

Last_SQL_Error: Error initializing relay log position: Binlog has bad magic number; It's not a binary log file that can be used by this version of MySQL

原因分析:當機,例如電源故障、主機板燒了等,或者非法關機,造成relay-bin檔案損壞

解決方法:同問題二

也可以設定relay_log_recovery = 1

slave從庫當機後,如果relay-log發生損壞,導致一部分中繼日誌沒有處理,就自動放棄未執行的relay-log,重新從master上獲取日誌,完成了中繼日誌的恢復。

常見問題之四

現象:從庫機器當機重啟後change master to 時出現Error (Code 1201): Could not initialize master info structure; more error messages can be found in the MySQL error log

或者ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository

原因分析:當機,例如電源故障、主機板燒了等,或者非法關機,造成master.info或者realy-log.info檔案損壞

解決方法:slave> reset slave all,重新change master to

預防措施:

1)配置檔案設定

relay_log_info_repository=table

master_info_repository=table

2

mysql5.6.5以前的版本mysql.slave_master_infomysql.slave_relay_log_info的儲存引擎是預設為MyISAM的,需要更改為InnoDB的儲存引擎

ALTER TABLE mysql.slave_master_info ENGINE=InnoDB;

ALTER TABLE mysql.slave_relay_log_info ENGINE=InnoDB;

mysql.slave_master_info 表將在sync_master_info events後被更新 。

mysql.slave_relay_log_info 表將在每個事務commit時被更新 。

常見問題之五

現象:主從原來binlog_format都是statement,將主庫binlog_format改為row後,從庫show slave status出現:

Last_Error: Error executing row event: 'Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT.'

原因分析:主庫binlog_formatrow,從庫binlog_formatstatement時,會出現上面的報錯 。

但是主庫binlog_formatstatement,從庫binlog_formatrow;或者主庫binlog_formatrow,從庫binlog_formatmixed就不會報錯。

If the your SQL thread is indeed configured with binlog_format=STATEMENT once it receives a ROW event it will stop.

The reason is that it would be unable to log that ROW event in STATEMENT format (sometimes we refer to this as ROW injection, which is either a BINLOG statement or a ROW event executed by the slave's SQL thread)

詳細原因參考:https://bugs.mysql.com/bug.php?id=69095

解決方法:

SLAVE> STOP SLAVE;

SLAVE> SET GLOBAL binlog_format=MIXED;

SLAVE> START SLAVE;

常見問題之六

現象:mysql5.6同步mysql5.5時出錯

Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log;

the first event 'mysql-bin.000001' at 4, the last event read from 'mysql-bin.000001' at 120, the last byte read from 'mysql-bin.000001' at 120.'

原因分析:為了解決軟硬體或者網路傳輸出錯,導致主伺服器上執行的sql語句與從伺服器上執行的sql語句不一致(稱為event corrupt)的問題,mysql5.6版本新增了replication event checksum功能 。當一個event被寫入binary log的時候,checksum也同時寫入binary log,然後在event透過網路傳輸到slave之後,再在slave上對其進行驗證並寫入slaverelay log 。由於每一步都記錄了eventchecksum,所以我們可以很快地找出問題所在。

mysql5.6.5以後的版本中binlog_checksum預設值是crc32,而之前的版本binlog_checksum預設值是none

解決方案:

Slave> set global binlog_checksum=none

常見問題之七

現象:磁碟滿了,手動清理binlog檔案和mysql-bin.index檔案後,

show binary logs為空,但是show master status正常。

mysql> show binary logs;

Empty set (0.00 sec)

mysql> show master status;

+------------------+-----------+--------------+------------------+

| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+------------------+-----------+--------------+------------------+

| mysql-bin.001385 | 987114584 | | |

+------------------+-----------+--------------+------------------+

原因分析:檢查mysql-bin.index檔案後,發現第一行空行 。解法很簡單,刪了第一行的空行,然後 flush binary logs 生成新的 index 檔案把 cache 失效掉,就可以了。

mysql原始碼rpl_master.cc:show_binlogs()有如下程式碼:

/* The file ends with EOF or empty line */

while ((length=my_b_gets(index_file, fname, sizeof(fname))) > 1)

空行被認為是檔案結束

預防措施:不要人工去刪除binlog,不要人工編輯mysql-bin.index檔案,除非你知道你在幹什麼,否者你就可能在給自己埋雷!

總結:DBA需要關注MySQL的每個新版本對binlog都有那些改進(比如5.6版本新增的gtid 特性,5.7版本Enhanced Multi-threaded Slaves ) ,詳細瞭解每個引數的含義,這樣遇到錯誤知其意,解決問題才能順手。

相關文章