mysql内核测试,MySQL 5.7内核复制中的一个小坑

问题背景

最近在写一个作为MySQL Slave的角色的程序,连接到MySQL Master使用MySQL复制协议来Dump Binlog事件流。很自然,这个程序在第一次运行的时候,其事务GTIDSet是空的,那么在和Master建立主从连接的时候,是无法正常建立的。原因是:

参考:https://github.com/mysql/mysql-server/blob/5.7/sql/rpl_binlog_sender.cc

Master判断一个Slave Dump请求合法必须满足两个条件:Slave请求的GTIDSet是Master Executed GTIDSet的一个子集

Master Purged GTIDSet是Slave请求的GTIDSet的一个子集

显然,程序第一次运行的时候无法满足条件2(只要Master存在Purged GTIDSet),一个比较自然的错误处理逻辑是:

如果Slave程序发现连接到Master报的错误码是ER_MASTER_HAS_PURGED_REQUIRED_GTIDS,对应错误信息是:The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.的时候,我们查询Master的Purged GTIDSet,将这个GTIDSet merge到本地,以merge后的GTIDSet作为新的开始位置请求Dump。把这个特殊场景考虑进程序的一个逻辑中,避免手动来处理。

但测试发现,MySQL Server(5.7.17)返回的错误码为:ER_MASTER_FATAL_ERROR_READING_BINLOG,但错误信息为:The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.。而ER_MASTER_FATAL_ERROR_READING_BINLOG其实是一个很宽泛的错误码,关键是在这个场景中,Master Dump线程还在check阶段(Binlog_sender::check_start_file()这个函数中),根本没到读取Binlog文件的环节。所以我们认为这是一个小坑!

Root cause追踪

参考:rpl_binlog_sender.cc,我们可以看到,当Master的Purged GTIDSet不是Slave请求GTIDSet的一个子集的时候,errmsg被设置为了期望的“The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.”。但error code是在set_fatal_error函数中设置的,我们继续看这个函数:

742     if (!gtid_state->get_lost_gtids()->is_subset(m_exclude_gtid))

743 {

744 errmsg= ER(ER_MASTER_HAS_PURGED_REQUIRED_GTIDS);

745 global_sid_lock->unlock();

746 set_fatal_error(errmsg);

747       return 1;

748 }

set_fatal_error函数实现:rpl_binlog_sender.h,可以看到error code被设置成了ER_MASTER_FATAL_ERROR_READING_BINLOG,也就是MySQL Server返回给应用程序的错误码和错误信息不匹配。

382   void set_fatal_error(const char *errmsg)

383 {

384 set_error(ER_MASTER_FATAL_ERROR_READING_BINLOG, errmsg);

385 }

最后是我们写的程序,期望根据error code来写处理逻辑行不通,只好修改成strcasecmp来字符串匹配。

642 len = cli_safe_read(g_mysql_, NULL);

643       if (len == packet_error || (long)len < 1) {

644 LOG_ERR("cli_safe_read failed: (%d - %d - %s).",

645 mysql_errno(g_mysql_),

646 ER_MASTER_HAS_PURGED_REQUIRED_GTIDS,

647 mysql_error(g_mysql_));

648         // TODO: why errno is incorrect!

649if (ER_MASTER_HAS_PURGED_REQUIRED_GTIDS == mysql_errno(g_mysql_)){

650 LOG_INF("Will try to merge purged gtidset next round!");

651 new_master_purged = true;

652 }

653         goto err_t;

654 }

上面这段程序,测试会得到MySQL Server端返回error code 1236,但是其实错误信息是error code 1789的内容。

cli_safe_read failed: (1236 - 1789 - The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的问题,我来给您详细讲解一下如何修改MySQL 5.7的参数。 MySQL 5.7的参数可以通过修改配置文件my.cnf来进行配置。my.cnf文件通常位于MySQL安装目录下的/etc或者/etc/mysql目录下。在Linux系统,可以通过vi或者nano等编辑器打开该文件进行修改。 修改MySQL的参数有两种方式:动态修改和静态修改。 动态修改是指在运行时直接修改MySQL的参数值,这种方式的优点是不需要重启MySQL服务,缺点是重启MySQL服务后,修改的参数值会失效。 静态修改是指在my.cnf文件修改MySQL的参数值,这种方式的优点是修改的参数值会持久化保存,即使重启MySQL服务后,修改的参数值也不会失效。缺点是需要重启MySQL服务才能生效。 下面是两种方式的具体操作步骤: 动态修改MySQL参数: 可以通过下面的命令动态修改MySQL的参数: ``` SET GLOBAL parameter_name=parameter_value; ``` 其,parameter_name为要修改的参数名,parameter_value为要修改的参数值。例如,要将max_connections参数修改为1000,可以使用下面的命令: ``` SET GLOBAL max_connections=1000; ``` 静态修改MySQL参数: 可以通过修改my.cnf文件来静态修改MySQL的参数。具体操作步骤如下: 1.使用编辑器打开my.cnf文件,例如: ``` sudo vi /etc/mysql/my.cnf ``` 2.找到要修改的参数行,例如: ``` max_connections=100 ``` 3.将参数值修改为需要的值,例如: ``` max_connections=1000 ``` 4.保存修改后的my.cnf文件。 5.重启MySQL服务,例如: ``` sudo service mysql restart ``` 这样,修改的参数值就会生效了。 希望以上内容能够对您有所帮助。如果您还有其他问题,可以随时向我提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值