一大早的,某從庫突然報出故障:SQL線程中斷!
查看從庫狀態:
mysql> show slave status\G Slave_IO_State: Waiting for master to send event Master_Log_File: mysql-bin.026023 Read_Master_Log_Pos: 230415889 Relay_Log_File: relay-bin.058946 Relay_Log_Pos: 54632056 Relay_Master_Log_File: mysql-bin.026002 Slave_IO_Running: Yes Slave_SQL_Running: No Last_Errno: 1452 Last_Error: Error 'Cannot add or update a child row: a foreign key constraint fails (`zabbix`.`trigger_discovery`, CONSTRAINT `c_trigger_discovery_2` FOREIGN KEY (`parent_triggerid`) REFERENCES `triggers` (`triggerid`) ON DELETE CASCADE)' on query. Default database: 'zabbix'. Query: 'insert into trigger_discovery (triggerdiscoveryid,triggerid,parent_triggerid,name) values (1677,26249,22532,'Free inodes is less than 20% on volume {#FSNAME}'), (1678,26250,22532,'Free inodes is less than 20% on volume {#FSNAME}'), (1679,26251,22532,'Free inodes is less than 20% on volume {#FSNAME}')' Exec_Master_Log_Pos: 54631910
重點關注報錯信息,定位問題,問題是:Cannot add or update a child row:a foreign key constraint fails ,涉及到的外鍵是:c_trigger_discovery_2
那這個外鍵的定義是什么呢?
報錯信息中也有列出:
trigger_discovery`, CONSTRAINT `c_trigger_discovery_2` FOREIGN KEY (`parent_triggerid`) REFERENCES `triggers` (`triggerid`) ON DELETE CASCADE
那明白了,是表trigger_discovery中的列`parent_triggerid`和表triggers中的列`triggerid`有外鍵關聯,現在這里的數據插入出現了問題
那為什么會出現問題?
繼續看報錯,錯誤是從這里開始的:
insert into trigger_discovery (triggerdiscoveryid,triggerid,parent_triggerid,name) values (1677,26249,22532,'Free inodes is less than 20% on volume {#FSNAME}')
上述外鍵對應的列parent_triggerid的值是22532,難道這個值在表triggers中有問題?
我們去表triggers中查看:
從庫 mysql> select * from triggers where triggerid=22532; Empty set (0.00 sec) 主庫 mysql> select * from triggers where triggerid=22532; +-----------+------------+--------------------------------------------------+-----+--------+-------+----------+------------+----------+-------+------------+------+-------------+-------+ | triggerid | expression | description | url | status | value | priority | lastchange | comments | error | templateid | type | value_flags | flags | +-----------+------------+--------------------------------------------------+-----+--------+-------+----------+------------+----------+-------+------------+------+-------------+-------+ | 22532 | {23251}<20 | Free inodes is less than 20% on volume {#FSNAME} | | 0 | 0 | 2 | 0 | | | 13272 | 0 | 1 | 2 | +-----------+------------+--------------------------------------------------+-----+--------+-------+----------+------------+----------+-------+------------+------+-------------+-------+ 1 row in set (0.00 sec)
果然,從庫中沒有這個值對應的信息,但主庫中是有的,原來是主從不一致導致的,從庫中缺失這個值,主庫中順利插入了,但數據傳到從庫后,從庫的外鍵約束限制了這一插入操作,所以SQL線程阻塞。
問題找到了,那怎么解決?
首先,為了讓從庫盡快恢復運行,就先把這個錯誤跳過吧:
mysql>SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; #跳過一個事務 mysql>start slave;
接下來就是主從數據不一致的問題,可以使用pt-table-checksum來檢查下不一致的數據,再進行同步,具體步驟如下:
在主庫執行: mysql>GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE,CREATE,DELETE,INSERT,UPDATE ON *.* TO 'USER'@'MASTER_HOST' identified by 'PASSWORD';
注:創建用戶,這些權限都是必須的,否則會報錯
shell> ./pt-table-checksum --host='master_host' --user='user' --password='password' --port='port' --databases=zabbix --ignore-tables=ignore_table --recursion-method=processlist
注:(1)因為涉及到的表太多,查看后發現很多表都有外鍵關聯,錯綜復雜,而且因為是監控表,即使丟失一些也沒什么關系,所以查出較大的且沒有外鍵關聯的表用ignore-tables選項排除,對其他表進行比對,如果表比較少的話直接指定--TABLES (2)recursion-method如果不設的話,會報錯:Diffs cannot be detected because no slaves were found. 其參數有四:processlist/hosts/dsn/no,用來決定查找slave的方式是show full processlist還是show slave hosts還是直接給出slave信息,具體用法在另一隨筆pt-table-checksum介紹中詳述
shell>./pt-table-sync --print --replicate=percona.checksums h=master_host,u=user,p=password,P=port h=slave_host,u=user,p=password,P=port --recursion-method=processlist >pt.log
注:最好使用--print,不要直接使用--execute,否則如果弄出問題,就更麻煩了,打印出直接執行的語句,去從庫執行就好了
將pt.log傳到從庫,直接執行,然后再次在主庫上進行一致性檢查,如果還有不一致的數據,記得登錄mysql去把checksums表清空,然后再次進行檢查同步,直到沒有不一致的數據。
當然,如果主從數據反復出現不一致的話,那就要先去檢查造成不一致的原因了,釜底抽薪才是硬道理。