MySQL高可用架構中,主庫復制是非常常見的一種。
當主庫宕機后,可以提升一個從庫作為新的主庫,保證服務可用性;同時可以通過擴展從庫,提高整個集群的QPS。
在主從復制架構下,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: 35ERROR: 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庫已讀取的master的binlogExec_Master_Log_Pos: 950583017 //在slave上已經執行的position位置點
停掉slave,以slave已經讀取的binlog文件,和已經執行的position為起點,重新設置同步。
Relay_Master_Log_File: mysql-bin.002540 //slave庫已讀取的master的binlogExec_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
預防措施
配置文件設置
relay_log_info_repository=table
master_info_repository=table
mysql5.6.5以前的版本mysql.slave_master_info和mysql.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_format是row,從庫binlog_format是statement時,會出現上面的報錯 。
但是主庫binlog_format是statement,從庫binlog_format是row;
或者主庫binlog_format是row,從庫binlog_format是mixed就不會報錯。
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 STATEMENTformat (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上對其進行驗證並寫入slave的relay log 。由於每一步都記錄了event和checksum,所以我們可以很快地找出問題所在。
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文件后,發現第一行空行 。
在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)
空行被認為是文件結束
(參考https://yq.aliyun.com/articles/213657文章)
預防措施
不要人工去刪除binlog,不要人工編輯mysql-bin.index文件,除非你知道你在干什么,否者你就可能在給自己埋雷!
總結
DBA需要關注MySQL的每個新版本對binlog都有那些改進(比如5.6版本添加的gtid 特性,5.7版本Enhanced Multi-threaded Slaves ) ,詳細了解每個參數的含義,這樣遇到錯誤知其意,解決問題才能順手。