mysql從庫伺服器down機報錯Could not parse relay log event entry

賀子_DBA時代發表於2017-03-13
環境介紹:
最近網站總是出問題,因為play服務總是跑著跑著就死了,於是經理嘗試把play跑在我的mysql這兩臺伺服器上(因為這兩臺伺服器的資源很空閒),可是沒想到才跑了半天,就把伺服器的128G記憶體耗盡,伺服器無法正常使用,輸入任何命令都報錯,無法分配記憶體,reboot都不可以,只能去機房強制關機了。。。
我這裡一兩臺,主主複製的mysql:
192.10.0.143
192.10.0.144
透過keepalived對映出來了vip:192.10.0.145,目前vip在144上。
重啟的是143.
啟動之後,mysql服務成功開啟了,可是主從狀態報錯,sql程式狀態為NO,如下:
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.144
Master_User: info_syncer
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000823
Read_Master_Log_Pos: 60049919
Relay_Log_File: mysql-relay-bin.000047
Relay_Log_Pos: 268334387
Relay_Master_Log_File: mysql-bin.000822
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 1594
Last_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.
Skip_Counter: 0
Exec_Master_Log_Pos: 268334100
Relay_Log_Space: 535066509
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1594
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.
Replicate_Ignore_Server_Ids:
Master_Server_Id: 2
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
1 row in set (0.00 sec)

ERROR: No query specified
報錯原因
從上面紅體字可以知道,由於從庫的異常關機,導致接收的主庫的二進位制日誌崩潰,進而導致從庫的relay日誌損壞,sql程式無法讀取,導致從庫的sql程式狀態為:NO。
問題解決:
MariaDB [(none)]> stop slave ;
Query OK, 0 rows affected (0.00 sec)
解決方法一: 
找到,第一行記錄了當前正在執行的log-relay檔名 
找到該檔案的下一個檔案 
使用mysqlbinlog檢視該檔案,在#98這行有Rotate to log-bin.000004 pos: 4等資訊,這就是目前slave停止的位置 ,或者
在slave上重新指定同步位置,重新執行:
change master to 
master_host='1.1.1.1',
master_user='repl',
master_password='111111',
master_port=3306,
master_log_file='log-bin.000004',
master_log_pos=4;
然後啟動slave,
start slave ;
解決方法二:
stop slave之後,重新reset slave;
檢視slave狀態,正常了。。。。。

reset slave到底做了什麼??
RESET SLAVE
官方的解釋如下
1)RESET SLAVE makes the slave forget its replication position in the master's binary log. This statement is meant to be used for a clean start: It clears the master info and relay log info repositories, deletes all the relay log files, and starts a new relay log file. It also resets to 0 the replication delay specified with the MASTER_DELAY option to CHANGE MASTER TO. To use RESET SLAVE, the slave replication threads must be stopped (use STOP SLAVE if necessary).
2)RESET SLAVE does not change any replication connection parameters such as master host, master port, master user, or master password, which are retained in memory. This means that START SLAVE can be issued without requiring a CHANGE MASTER TO statement following
reset slave
其實,它是直接刪除master.info和relay-log.info檔案,並刪除所有的relay log,然後重新生成一個新的relay log,即使relay log中還有SQL沒有被SQL執行緒apply完。
但是RESET SLAVE有個問題,它雖然刪除了上述檔案,但記憶體中的change master資訊並沒有刪除,此時,可直接執行start slave,但因為刪除了master.info和relay-log.info,它會從頭開始接受主的binlog並應用。(注意:這裡所說的從頭是說:reset的時候,正在接受的主的binlog,從新接受這個binlog).如果SQL thread 正在複製臨時表的過程中,執行了stop slave ,並且執行了reset slave,這些被複制的臨時表將被刪除。
題外話:reset master 做了什麼?
1. reset master 將刪除日誌索引檔案中記錄的所有binlog檔案,建立一個新的日誌檔案 起始值從000001 開始,
2. reset master 不能用於有任何slave 正在執行的主從關係的主庫。因為在slave 執行時刻 reset master 命令不被支援,reset master 將master 的binlog從000001 開始記錄,slave 記錄的master log 則是reset master 時主庫的最新的binlog,從庫會報錯無法找的指定的binlog檔案。
繼續解決問題:
主從狀態正常後,檢視告警日誌,發現報錯
告警日誌報錯:表crashed,需要repaire
ERROR] log.logs: 1 client is using or hasn't closed the table properly
170310 11:54:14 [ERROR] mysqld: Table './log/oprlogs' is marked as crashed and should be repaired
170310 11:54:14 [Warning] Checking table: './log/oprlogs'
170310 11:54:14 [ERROR] log.oprlogs: 1 client is using or hasn't closed the table properly
170310 11:54:14 [ERROR] log.oprlogs: Size of datafile is: 1656831165 Should be: 1656830670
170310 11:54:47 [ERROR] log.oprlogs: Found 495 deleted space. Should be 0
170310 11:54:47 [ERROR] log.oprlogs: Found 15 deleted blocks Should be: 0
170310 11:54:47 [ERROR] log.oprlogs: Found 50207005 key parts. Should be: 50206990
170310 11:54:47 [ERROR] mysqld: Table './log/history' is marked as crashed and should be repaired
170310 11:54:47 [Warning] Checking table: './log/history'
170310 11:54:47 [ERROR] log.history: 1 client is using or hasn't closed the table properly
直接repair table table_name就可以了。。。。,依次修復日誌中出現的被標記為crashed的表。
MariaDB [(none)]> repair table log.logs;
下面講下修復 table:整理自網路。。。。。
多數情況下,資料庫被破壞只是指索引檔案受到了破壞,真正的資料被破壞掉的情況非常少。大多數形式的資料庫破壞的的修復相當簡單。
和前面的校驗一樣,修復的方式也有三種。
下面講的方法只對MyISAM格式的表有效。其他型別的損壞需要從備份中恢復。
1,REPAIR TABLE SQL statement(mysql服務必須處於執行狀態)。
2,命令mysqlcheck(mysql服務可以處於執行狀態)。
3,命令myisamchk(必須停掉mysql服務,或者所操作的表處於不活動狀態)。
在修復表的時候,最好先作一下備份。所以你需要兩倍於原始表大小的硬碟空間。請確保在進行修復前你的硬碟空間還沒有用完。
1>用”repair table”方式修復
語法:repair table 表名 [選項]
選項如下:
QUICK 用在資料表還沒被修改的情況下,速度最快
EXTENDED 試圖去恢復每個資料行,會產生一些垃圾資料行,萬般無奈的情況下用
USE_FRM 用在.MYI檔案丟失或者頭部受到破壞的情況下。利用.frm的定義來重建索引
多數情況下,簡單得用”repair table tablename”不加選項就可以搞定問題。但是當.MYI檔案丟失或者頭部受到破壞時,這樣的方式不管用,例如:
mysql> REPAIR TABLE mytable;
+————————-+——–+———-+———————————————+
| Table | Op | Msg_type | Msg_text |
+————————-+——–+———-+———————————————+
| sports_results.mytable | repair | error | Can’t find file: ‘mytable.MYI’ (errno: 2) |
+————————-+——–+———-+———————————————+
修復失敗的原因時索引檔案丟失或者其頭部遭到了破壞,為了利用相關定義檔案來修復,需要用USE_FRM選項。例如:
mysql> REPAIR TABLE mytable USE_FRM;
+————————-+——–+———-+————————————+
| Table | Op | Msg_type | Msg_text |
+————————-+——–+———-+————————————+
| sports_results.mytable | repair | warning | Number of rows changed from 0 to 2 |
| sports_results.mytable | repair | status | OK |
+————————-+——–+———-+————————————+
我們可以看到Msg_test表項的輸出資訊”ok”,表名已經成功修復受損表。
2>用mysql內建命令mysqlcheck來修復
當mysql服務在執行時,也可以用mysql內建命令mysqlcheck來修復。
語法:mysqlcheck -r 資料庫名 表名 -uuser -ppass
%mysqlcheck -r sports_results mytable -uuser -ppass
sports_results.mytable OK
利用mysqlcheck可以一次性修復多個表。只要在資料庫名後列出相應表名即可(用空格隔開)。或者資料庫名後不加表名,將會修復資料庫中的所有表,例如:
%mysqlcheck -r sports_results mytable events -uuser -ppass
sports_results.mytable OK
sports_results.events OK
%mysqlcheck -r sports_results -uuser -ppass
sports_results.mytable OK
sports_results.events OK
3>用myisamchk修復
用這種方式時,mysql服務必須停掉,或者所操作的表處於不活動狀態(選項skip-external-locking沒被使用)。記著一定要在相關.MYI檔案的路徑下或者自己定義其路徑。
語法:myisamchk [選項] [表名]
下面是其選項和描述
–backup, -B 在進行修復前作相關表得備份
–correct-checksum 糾正校驗和
–data-file-length=#, -D # 重建表時,指定資料檔案得最大長度
–extend-check, -e 試圖去恢復每個資料行,會產生一些垃圾資料行,萬般無奈的情況下用
–force, -f 當遇到檔名相同的.TMD檔案時,將其覆蓋掉。
keys-used=#, -k # 指定所用的keys可加快處理速度,每個二進位制位代表一個key.第一個key為0
–recover, -r 最常用的選項,大多數破壞都可以透過它來修復。如果你的記憶體足夠大,可以增大引數sort_buffer_size的值來加快恢復的速度。但是遇到唯一鍵由於破壞而不唯一 的表時,這種方式不管用。
–safe-recover -o 最徹底的修復方式,但是比-r方式慢,一般在-r修復失敗後才使用。這種方式讀出 所有的行,並以行為基礎來重建索引。它的硬碟空間需求比-r方式稍微小一點,因 為它沒建立分類快取。你可以增加key_buffer_size的值來加快修復的速度。
–sort-recover, -n mysql用它類分類索引,儘管結果是臨時檔案會非常大
–character-sets-dir=… 包含字符集設定的目錄
–set-character-set=name 為索引定義一個新的字符集
–tmpdir=path, -t 如果你不想用環境變數TMPDIR的值的話,可以自定義臨時檔案的存放位置
–quick, -q 最快的修復方式,當資料檔案沒有被修改時用,當存在多鍵時,第二個-q將會修改 資料檔案
–unpack, -u 解開被myisampack打包的檔案
myisamchk應用的一個例子
% myisamchk -r mytable
- recovering (with keycache) MyISAM-table ‘mytable.MYI’
題外引申。。。
REPAIR TABLE `table_name` 修復表 
OPTIMIZE TABLE `table_name` 最佳化表 
REPAIR TABLE語句被寫入二進位制日誌中,除非使用了自選的NO_WRITE_TO_BINLOG關鍵詞(或其別名LOCAL)。
REPAIR TABLE 用於修復被破壞的表。 
OPTIMIZE TABLE 用於回收閒置的資料庫空間,當表上的資料行被刪除時,所佔據的磁碟空間並沒有立即被回收,使用了OPTIMIZE TABLE命令後這些空間將被回收,並且對磁碟上的資料行進行重排(注意:是磁碟上,而非資料庫)。 多數時間並不需要執行OPTIMIZE TABLE,只需在批次刪除資料行之後,或定期(每週一次或每月一次)進行一次資料表最佳化操作即可,只對那些特定的表執行。
從新chang 的日誌位置和日誌號
無論是新搭建主從複製,還是
在複製之前要先鎖定資料,然後再獲得相關的日誌資訊(FILE & POSITION):
mysql> FLUSH TABLES WITH READ LOCK; 鎖表,一般新加主從的時候,保重一致性
MariaDB [log]> SHOW MASTER STATUS;
+------------------+-----------+--------------+--------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+-----------+--------------+--------------------------+
| mysql-bin.000825 | 287366341 | | mysql,information_schema |
+------------------+-----------+--------------+--------------------------+
1 row in set (0.00 sec)
接下來複製資料檔案時,如果是MyISAM表型別的話,直接複製即可;如果是InnoDB表型別的話,一定要先停止MySQL服務再複製,否則複製檔案可能無法使用。把複製的資料檔案直接複製到從伺服器的資料目錄。
最後還需要再指定一下日誌資訊:
mysql> CHANGE MASTER TO
MASTER_HOST="<MASTER_HOST>",
MASTER_USER="<SLAVE_USER>",
MASTER_PASSWORD="<SLAVE_PASSWORD>",
MASTER_LOG_FILE="<FILE>",
MASTER_LOG_POS=<POSITION>;
在主伺服器上直接複製資料檔案雖然很快,但需要鎖表或者停止服務,這會影響線上服務。如果先前已經有了從伺服器,那麼可以用舊的從伺服器做母本來克隆新的從伺服器:
先在舊的從伺服器上查詢日誌資訊:
mysql> SHOW SLAVE STATUS;
我們需要的是其中的Relay_Master_Log_File & Exec_Master_Log_Pos。
然後在舊的從伺服器上按照前面的方法得到資料,可以先stop slave,然後複製資料並在新的從伺服器上還原。
接著在新的從伺服器上設定日誌資訊:
mysql> CHANGE MASTER TO
MASTER_HOST="<MASTER_HOST>",
MASTER_USER="<SLAVE_USER>",
MASTER_PASSWORD="<SLAVE_PASSWORD>",
MASTER_LOG_FILE="<Relay_Master_Log_File>",
MASTER_LOG_POS=<Exec_Master_Log_Pos>;
不管用那個方法,最後記得在從伺服器上啟動複製,並檢查工作是否正常:
mysql> START SLAVE;
mysql> SHOW SLAVE STATUS;
注意:
MariaDB [(none)]> show slave status\G;
顯示的Master_Log_File和 Read_Master_Log_Pos 這兩個只對應這master
show master status\G;的檔案號和位置

*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.143
Master_User: info_syncer
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000019
Read_Master_Log_Pos: 1038
總結:萬不得一不要在服務還沒有停的情況下去停伺服器,尤其是資料庫,否則會出現意想不到的錯誤,但是當伺服器出現不可解決的問題的時候,一定要果斷的去重啟,不要猶豫,難免出現更嚴重的問題,再就是play或者tomcat等等這些服務最好分開跑,以免互相影響。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29654823/viewspace-2135202/,如需轉載,請註明出處,否則將追究法律責任。

相關文章