mysql运维-slave_skip_errors

1 简介

    mysql在主从复制过程中,由于各种的原因,从服务器可能会遇到执行BINLOG中的SQL出错的情况,在默认情况下,服务器会停止复制进程,不再进行同步,等到用户自行来处理。

    slave-skip-errors的作用就是用来定义复制过程中从服务器可以自动跳过的错误号,当复制过程中遇到定义的错误号,就可以自动跳过,直接执行后面的SQL语句。

2 官方参考


Command-Line Format

–slave-skip-errors=name

System Variable Name

slave_skip_errors

Variable Scope

Global

Dynamic Variable

No

 

Permitted Values

Type

string

Default

OFF

Valid Values

OFF

[list of error codes]

all

ddl_exist_errors

    slave_skip_errors选项有四个可用值,分别为:off,all,ErorCode,ddl_exist_errors

     默认情况下该参数值是off,我们可以列出具体的error code,也可以选择all,mysql5.6及MySQL Cluster NDB 7.3以及后续版本增加了参数ddl_exist_errors,该参数包含一系列error code(1007,1008,1050,1051,1054,1060,1061,1068,1094,1146)

    一些error code代表的错误如下:

    1007:数据库已存在,创建数据库失败

    1008:数据库不存在,删除数据库失败

    1050:数据表已存在,创建数据表失败

    1051:数据表不存在,删除数据表失败

    1054:字段不存在,或程序文件跟数据库有冲突

    1060:字段重复,导致无法插入

    1061:重复键名

    1068:定义了多个主键

    1094:位置线程ID

    1146:数据表缺失,请恢复数据库

    1053:复制过程中主服务器宕机

    1062:主键冲突 Duplicate entry ‘%s’ for key %d    my.cnf中的写法:

[sql] view plain copy

  1. slave_skip_errors=1062,1053  
  2. slave_skip_errors=all  
  3. slave_skip_errors=ddl_exist_errors  

    作为mysql启动参数的写法:

[sql] view plain copy

  1. –slave-skip-errors=1062,1053  
  2. –slave-skip-errors=all  
  3. –slave-skip-errors=ddl_exist_errors  

    从数据库中查看该参数的值:

[sql] view plain copy

  1. mysql> show variables like ‘slave_skip%’;  
  2. +——————-+——-+  
  3. | Variable_name     | Value |  
  4. +——————-+——-+  
  5. | slave_skip_errors | 1007  |  
  6. +——————-+——-+  

3 举例分析

    3.1 测试说明
    配置好MySQL主从同步,然后在从上写入数据,造成主从不一致。
    3.2 准备测试表结构
    在主机上创建表:

[sql] view plain copy

  1. create table replication (c1 int not null primary key, c2 varchar(10));  

    3.3 准备测试数据

    在主机上插入基础数据

[sql] view plain copy

  1. mysql> insert into replication values (1, ‘test1’);  
  2. mysql> insert into replication values (2, ‘test2’);  

    此时,主机从机replication表里面都有两条记录
    3.4 开始测试
    从机插入一条记录

[sql] view plain copy

  1. mysql> insert into replication values (3, ‘test3’);  

    然后在主机上执行相同的操作

[sql] view plain copy

  1. mysql> insert into replication values (3, ‘test3’);  

    在从机上查看复制状态

[sql] view plain copy

  1. mysql> show slave status \G  
  2. *************************** 1. row ***************************  
  3.                Slave_IO_State: Waiting for master to send event  
  4.                   Master_Host: 192.168.1.222  
  5.                   Master_User: repl  
  6.                   Master_Port: 3306  
  7.                 Connect_Retry: 60  
  8.               Master_Log_File: mysql-bin.000003  
  9.           Read_Master_Log_Pos: 16700  
  10.                Relay_Log_File: mysql-relay-bin.000003  
  11.                 Relay_Log_Pos: 16595  
  12.         Relay_Master_Log_File: mysql-bin.000003  
  13.              Slave_IO_Running: Yes  
  14.             Slave_SQL_Running: No  
  15.               Replicate_Do_DB:   
  16.           Replicate_Ignore_DB:   
  17.            Replicate_Do_Table:   
  18.        Replicate_Ignore_Table: mysql.ibbackup_binlog_marker  
  19.       Replicate_Wild_Do_Table:   
  20.   Replicate_Wild_Ignore_Table: mysql.backup_%  
  21.                    Last_Errno: 1062  
  22.                    Last_Error: Error ‘Duplicate entry ‘3‘ for key ‘PRIMARY on query. Default database‘test’. Query: ‘insert into replication values (3, ‘test3‘)’  
  23.                  Skip_Counter: 0  
  24.           Exec_Master_Log_Pos: 16425  
  25.               Relay_Log_Space: 17544  

    可以看到:sql线程已经停止工作 Slave_SQL_Running: No

                        错误号为:Last_Errno: 1062

                        错误信息为:Last_Error: Error ‘Duplicate entry ‘3’ for key ‘PRIMARY” on query. Default database: ‘test’. Query: ‘insert into replication values (3, ‘test3′)’

    如果我们在my.cnf中加入如下选项,则可跳过此错误,数据同步继续进行。

[sql] view plain copy

  1. [mysqld]  
  2. slave_skip_errors=1062  

    具体测试方法同上,大家可自己验证。

4 从backup恢复时从机复制出错的一些解释

    mysql企业版备份工具meb提供在线热备功能,如果在备份过程中执行ddl操作,从机需要从主机的备份恢复时可能会异常,从而导致从机同步数据失败。原因是从机恢复时需要先从备份文件恢复(包含备份过程中执行的ddl语句),同步时不是从全备后的最后一个位置同步,而是从ddl的上个位置同步,如果再次执行该ddl语句在从机上不会造成冲突,则同步继续,如果会造成冲突,同步终止。解决此冲突的办法是在my.cnf文件中加入一行

[sql] view plain copy

  1. [mysqld]  
  2. slave_skip_errors=ddl_exist_errors  

5 注意事项

    5.1 该参数为全局静态参数,不能动态调整,可在my.cnf中加入该参数列表后重启mysql服务器生效。

    5.2 必须注意的是,启动这个参数,如果处理不当,很可能造成主从数据库的数据不同步,在应用中需要根据实际情况,如果对数据完整性要求不是很严格,那么这个选项确实可以减轻维护的成本


解决办法一、
Slave_SQL_Running: No
1.程序可能在slave上进行了写操作
2.也可能是slave机器重起后,事务回滚造成的.



 Last_SQL_Errno: 1677
 Last_SQL_Error: Column 1 of table 'test.t' cannot be converted from type 'int' to type 'bigint(20)'
解决方法:这个案例是从网上找到的,自己动手实验了一把。从错误信息来看表面上是由于在slave上无法执行一条转换字段类型的SQL语句。实际上并不是有这种语句直接引起的,而是间接引起的(之前某些操作导致主从表字段类型不一致,接下来对这个表进行DML时就会报错)。它的意思是在对这个表t进行DML操作时,发现主从上表结果不一致,比如这里是说在主上t的字段1是int类型,但是从上t的字段1是bigint类型,所以报错。那么为什么要报错呢?这是从安全角度考虑,因为如果字段类型不一致可能会导致数据截断之类的问题。那么解决方法呢?通过参数slave_type_conversions进行控制,它有三种取值:
ALL_LOSSY:仅支持有损转换,什么叫有损?比如一个值本来是bigint存储为9999999999999,现在转换为int类型势必会要截断从而导致数据不一致。
ALL_NON_LOSSY:仅支持无损转换,只能在无损的情况下才能进行转换
ALL_LOSSY,ALL_NON_LOSSY:有损/无算转换都支持
空,即不设置这个参数:必须主从的字段类型一模一样。
注意: 前面说的这几中情况都只在binlog_format=ROW的情况下才有效。


 Last_SQL_Errno: 1194
 Last_SQL_Error: Error 'Table 'traincenter' is marked as crashed and should be repaired' on query. Default database: 'basketballman'. Query: 'update traincenter set points='4',pointstime='1361912066' where uid = '1847482697' limit 1'
 解决方法:myisam表traincenter损坏,直接repair table即可。至于为什么myisam类型表比innodb更容易损坏,我觉得有两个原因:1,innodb有double write机制,损坏或者half write的页可以用它恢复,第二innodb是事务引擎,都有操作都是事务的,而myisam是非事务的,存在写一半但是操作终止情况。


 Last_IO_Errno: 1236
 Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'
 解决方法:主库上的binlog文件已经不存在但是在index file中确有相应记录存在。我这里发生这个错误的原因在于由于复制中断时间很长,报警出来一直没人处理,这个中断时间超过master上binlog超期时间,等恢复复制时需要的binlog已经由于其超期而被删掉,没办法只好重建这个实例了。以大家都要引以为戒
stop slave;
reset slave; 
slave start;


 Last_IO_Errno: 1593
 Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id option must be used on slave but this does not always make sense; please check the manual before using it).
 解决方法:主从配置的server-id一样,而在主从复制环境中server-id一样的binlog events都会被过滤掉。具体server-id的含义可以了解一下复制原理。这个一般是因为拷贝配置文件时忘记修改server-id导致,遇到这类问题也比较容易,平时操作谨慎一点即可。


 Last_Errno: 1053
 Last_Error: Query partially completed on the master (error on master: 1053) and was aborted. There is a chance that your master is inconsistent at this point. If you are sure that your master is ok, run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; . Query: 'insert into ...
 解决方法:查询在master上部分完成,然后终止了。这马上又能想到是myisam表,结果也正是这样。由于myisam不支持事务所以可能存在一个查询完成一部分然后失败的情况。解决方法一般也就是提示信息给出的跳过一个binlog event。不过确认跳过之前最好还是查询一下master上是否真的存在相应的记录,因为错误信息同时还会给出它认为在master上执行一部分然后终止的查询语句。


 Last_SQL_Errno: 1666
 Last_SQL_Error: Error executing row event: 'Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT.' 
 解决方法:这个案例的背景是做一个ABC结构的复制,B、C中设定的binlog_format=statement,A中的是MIXED,所以当B尝试重做A过来的relay log,然后记录binlog(传给C)时发现relay log的binlog_format与自己设定的binlog_format不一致。我当时就是直接先更改BC的binlog_format=MIXED解决。


 Last_Errno: 1032
 Last_Error: Could not execute Update_rows event on table db.table; Can't find record in 'table', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000064, end_log_pos 158847
解决方法:这个是在binlog_format=row复制下发生的。原因是因为row格式复制是最严格的,所以在mysql看来如果在从库上找不到要更新的这条记录,那么就代表主从数据不一致,因此报错。另外顺便说一句,对于row格式binlog,如果某个更新操作实际上并没有更新行,这个操作是不会记binlog的,因为row格式的binlog宗旨就是只记录发生了改变的行。所以这个解决办法根据你自己实际应用来定,最好的方法还是重做slave吧,这样更放心。


 Last_Errno: 28
 Last_Error: Error in Append_block event: write to '/tmp/SQL_LOAD-32343798-72213798-1.data' failed
 解决方法: 首先说错误原因:主库执行load data infile,同步到从库后load data infile存放的文件默认是放在/tmp(由参数slave_load_tmpdir控制),而/tmp空间不够因此报错。因此只要将从库上slave_load_tmpdir设置到一个磁盘空间足够大的分区就行。