mysql忽略可用性_MySQL:slave_skip_errors参数对MGR可用性的影响

---

整个问题提出和测试由 @gc @甘露寺的姑子@乙酉 完成,文档记录由@gc @乙酉完成。

我只是进行了问题分析和文档整理

---

欢迎关注我的《深入理解MySQL主从原理 32讲 》,如下:

![image.png](https://upload-images.jianshu.io/upload_images/7398834-0ffa3bdc078cddf4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

如果图片不能显示可查看下面链接:

https://www.jianshu.com/p/d636215d767f

###一、案例描述

MGR在遇到表不存在的情况下,节点没有退出节点而是爆出一个警告,并且节点状态也正常,警告如下:

```

2019-10-17T21:16:11.564211+08:00 10 [Warning] Slave SQL for channel

group_replication_applier': Worker 1 failed executing transaction 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:8' at master log , end_log_pos 220;

Error executing row event: 'Table 'test.a_1' doesn't exist', Error_code: 1146

```

集群状态如下:

```

[root@mysql.sock][test]>select * from performance_schema.replication_group_members;

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

| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |

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

| group_replication_applier | 9fd479bb-f0d8-11e9-9381-000c29105312 | mysql_1 | 3306 | ONLINE |

| group_replication_applier | a8833a96-f0d8-11e9-a9f4-000c291fd9a5 | mysql_2 | 3306 | ONLINE |

| group_replication_applier | b2968fe2-f0d8-11e9-a8ff-000c29c89e42 | mysql_3 | 3306 | ONLINE |

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

3 rows in set (0.00 sec)

```

当时觉得很奇怪,我们知道这种错误即便是在主从情况下也是报错的SQL线程退出的,MGR居然还能在线,这种情况数据已经不同步了,应该报错并且剔除节点才对。

###二、问题分析

随即一些感兴趣的同学马上进行了测试,测试结果和上面不一致,测试结果是报错而不是出警告如下:

```

2019-10-17T09:16:34.317542Z 84 [ERROR] Slave SQL for channel

'group_replication_applier': Error executing row event:

'Table 'test.emp1' doesn't exist', Error_code: 1146

```

并且这种情况表不存在的节点已经被剔除掉了。下面是正常情况的节点状态:

```

secondary 1节点:

[root@mysql.sock][test]>select * from performance_schema.replication_group_members;

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

| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |

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

| group_replication_applier | a8833a96-f0d8-11e9-a9f4-000c291fd9a5 | mysql_2 | 3306 | ERROR |

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

1 row in set (0.00 sec)

secondary 2节点:

[root@mysql.sock][test]>select * from performance_schema.replication_group_members;

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

| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |

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

| group_replication_applier | b2968fe2-f0d8-11e9-a8ff-000c29c89e42 | mysql_3 | 3306 | ERROR |

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

1 row in set (0.00 sec)

```

那么疑问就是为什么同样是MGR一个是警告一个是错误呢,并且前者还能处于正常同步状态。不错看到题目就知道这里和slave_skip_errors参数有关。

###三、测试模拟

我们知道再Master-Slave中如果遇到从库表不存在肯定是报错的,除非设置slave_skip_errors参数,当然我在线上重来没有设置过这个参数,并且通过这个案例我们发现本参数对MGR也有影响,如下测试方法:

我们在3个节点都开启slave-skip-errors= ddl_exist_errors

如下图:

![image.png](https://upload-images.jianshu.io/upload_images/7398834-6e2ac440f645c4f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

然后搭建3节点single-primary模式的MGR集群。

![image.png](https://upload-images.jianshu.io/upload_images/7398834-ddf7f768814eb07d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

集群搭建正常。

然后执行如下操作:

```

[root@mysql.sock][(none)]>set sql_log_bin=0;

Query OK, 0 rows affected (0.00 sec)

[root@mysql.sock][(none)]>create table test.a_1(id bigint auto_increment primary key,name varchar(20));

Query OK, 0 rows affected (0.01 sec)

[root@mysql.sock][(none)]>set sql_log_bin=1;

Query OK, 0 rows affected (0.00 sec)

```

此时primary节点是有a_1表的,但是因为binlog关闭的原因,两个secondary节点是不存在a_1表的。

然后我们插入数据:

```

[root@mysql.sock][test]>insert into test.a_1 values(null,'tom');

Query OK, 1 row affected (0.02 sec)

```

此时,primary节点因为存在a_1表,所以能够插入,但是两个secondary节点不存在a_1表,所以插入是失败的。数据产生不一致。正常情况下这种数据不一致会导致2个secondary节点被提出集群才对。但是实际上3个节点都是正常的,集群并没有失效。

```

[root@mysql.sock][test]>select * from test.a_1;

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

| id | name |

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

|  1 | tom  |

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

1 row in set (0.00 sec)

[root@mysql.sock][test]>select * from performance_schema.replication_group_members;

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

| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |

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

| group_replication_applier | 9fd479bb-f0d8-11e9-9381-000c29105312 | mysql_1     |        3306 | ONLINE       |

| group_replication_applier | a8833a96-f0d8-11e9-a9f4-000c291fd9a5 | mysql_2     |        3306 | ONLINE       |

| group_replication_applier | b2968fe2-f0d8-11e9-a8ff-000c29c89e42 | mysql_3     |        3306 | ONLINE       |

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

3 rows in set (0.00 sec)

```

此时去2个secondary节点读取test.a_1表,表是不存在的。

```

secondary 1:

[root@mysql.sock][test]>select * from test.a_1;

ERROR 1146 (42S02): Table 'test.a_1' doesn't exist

[root@mysql.sock][test]>

secondary 2:

[root@mysql.sock][test]>select * from test.a_1;

ERROR 1146 (42S02): Table 'test.a_1' doesn't exist

```

error log输出信息:(set global log_error_verbosity = 3;)

```

2019-10-17T21:16:11.564211+08:00 10 [Warning] Slave SQL for channel

'group_replication_applier': Worker 1 failed executing transaction 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:8' at master log ,

end_log_pos 220; Error executing row event: 'Table 'test.a_1' doesn't exist', Error_code: 1146

```

###四、slave_skip_errors源码生效点

这个设置在Rows_log_event::do_apply_event 函数中生效,也就是DML Event开始应用的时候生效,这是常规的SQL线程(或者Worker线程)调用的。

```

#ifdef HAVE_REPLICATION

if (opt_slave_skip_errors)

add_slave_skip_errors(opt_slave_skip_errors);

#endif

if (open_and_lock_tables(thd, rli->tables_to_lock, 0))//打开表

{

uint actual_error= thd->get_stmt_da()->mysql_errno();

if (thd->is_slave_error || thd->is_fatal_error)

{

if (ignored_error_code(actual_error)) //这里受到 slave_skip_errors 参数控制 ignored_error_code会将slave_skip_errors的参数设置读取出来

{

if (log_warnings > 1)

rli->report(WARNING_LEVEL, actual_error,

"Error executing row event: '%s'",

(actual_error ? thd->get_stmt_da()->message_text() :

"unexpected success or fatal error"));

thd->get_stmt_da()->reset_condition_info(thd);

clear_all_errors(thd, const_cast(rli));

error= 0;

goto end;

}

else

{

rli->report(ERROR_LEVEL, actual_error,

"Error executing row event: '%s'",

(actual_error ? thd->get_stmt_da()->message_text() :

"unexpected success or fatal error"));

thd->is_slave_error= 1;

const_cast(rli)->slave_close_thread_tables(thd);

DBUG_RETURN(actual_error);

}

}

```

可以看到MGR的执行逻辑受到了该参数的影响。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7728585/viewspace-2660860/,如需转载,请注明出处,否则将追究法律责任。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值