MySQL:5.6同步到5.7 GTID报错

7 篇文章 0 订阅

问题描述和处理

同步到的版本为5.7.35,按理说在5.7种还是一个比较新的版本了,报错大概如下:

2023-05-14T05:09:47.427031Z 12 [Note] Multi-threaded slave statistics for channel '': seconds elapsed = 163; events assigned = 67585; worker queues filled over overrun level = 0; waited due
 a Worker queue full = 0; waited due the total size = 0; waited at clock conflicts = 0 waited (count) when Workers occupied = 0 waited when Workers occupied = 0
2023-05-14T05:09:48.526341Z 12 [ERROR] Transaction is tagged with inconsistent logical timestamps: sequence_number (7870797233) <= last_committed (2957740090370948108)
2023-05-14T05:09:48.526416Z 12 [ERROR] Slave SQL for channel '': ... The slave coordinator and worker threads are stopped, possibly leaving data in inconsistent state. A restart should rest
ore consistency automatically, although using non-transactional storage for data or info tables or DDL queries could lead to problems. In such cases you have to examine your data (see docum
entation for details). Error_code: 1756

从报错来看肯定属于逻辑时钟并发的问题,因为在5.6中gtid event没有last commit和seq number,因此可能并发的时候遇到了问题,因此简单的关闭了MTS并发回放就可以了继续了。

分析原因

实际上在代码中对于GTID不包含的last commit和seq number的情况,在初始化gtid event的时候应该将其初始化为0(SEQ_UNINIT= 0;
),并且并发的时候也会有相关判定如下:

那么这个条件不可能成立,因为last_committed == SEQ_UNINIT,也就不会报错,但是实际上这里报错了。从报错的seq number和last commit值来看,应该是内存越界访问的结果,否则不会有这种很大的seq number和last commit(sequence_number (7870797233) 、 last_committed (2957740090370948108))。

那么接下来就是看看为什么会出现这种情况,也就是gtid event的初始化遇到了什么问题。实际上问题就出在binary_log::Gtid_event::Gtid_event这个构造函数中,如下

这里ptr_buffer + LOGICAL_TIMESTAMP_TYPECODE_LENGTH +
LOGICAL_TIMESTAMP_LENGTH <= buffer + event_len的含义是,如果本次获取的gtid event的长度小于5.7格式的gtid event的长度就不要执行last commit和seq number的赋值,因为5.7的gtid event 包含了16字节的last commit和seq number,还包含了1字节的typecode,总共比5.6的gtid event 大17字节。
但是这里的问题在于buffer + event_len中buffer的位置已经是去掉event header的长度,也就是计算的是event_len的长度+event header的长度,如下,

而event header为19个字节,因此判定的实际上就是是17字节<=19字节,这个条件是一定会满足的,因此这里出现了buffer的越界访问,当越界访问的值也满足第二个条件的时候,就会进行last commit和seq number的赋值,但是为越界访问,因此值不确定,比如看到的如下,

当不确定的值遇到last commit比seq number还大的情况就会报错了。那么这里实际上稍微改一下

就可以了,LOG_EVENT_HEADER_LEN则为19字节。修改编译后5.6到5.7的同步可以正常运行,再次查看last commit和seq number就是0了。


这也是正常的因为5.6就没有last commit和seq number。并且还需要测试5.7到5.7的主从同步,是否gtid event能够拿到正确的值,因为如果这里过滤异常了,则5.7到5.7的同步seq number和last commit 也可能初始化为0,也就是测试修改是否正确,查看seq number和last commit如下,

能够初始化为正常的值。

提问一个问题

C语言内存越界不一定会触发SIGSEGV信号的原因是因为,SIGSEGV是由操作系统抛出的信号,当程序执行访问了无效的内存地址时,操作系统会检测到这种异常情况,并向进程发送SIGSEGV信号。

然而,在C语言中,对于数组和指针的访问并未受到强制的边界检查,如果程序发生内存越界,也许不会直接导致程序崩溃,而是可能引起一些意想不到的结果,比如修改了其他变量的值、出现奇怪的计算结果等。这种情况被称为未定义行为。

因此,当程序存在内存越界的问题时,不一定会立即引发SIGSEGV信号,而是要视具体情况而定,有时候会在操作系统的内存保护机制下触发SIGSEGV信号,有时候则不会。为了避免内存越界带来的未定义行为,应该在编写代码时尽量避免这种情况的出现,或者通过调试工具等手段进行检测和修复。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

出世&入世

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值