MySQL:非双1情况下事务丢失一列

2022-09-03  本文已影响0人  重庆八怪

水平有限,仅供参考


最近虽然没有写文章,但是还是遇到很多各种各样的,也不是所有的问题都找到了原因。这里先简单分享一个如下,下次再分享其他的。

事务丢失一列

这个问题实际上就是A->B->C的级联库,其中B库设置了非双1,且版本为8.0.**。假设当前A的GTID为 A:1-10,B的GTID为 A:1-10,C的GTID为 A:1-10。

当B由于OOM导致了Crash recovery后,恢复后发现一个奇特的现象,B的GTID依旧为 A:1-10,但是其中的binlog却不包含A:10这个事务,并且A:10的这个事务的数据修改也没有在B库中存在。

简单点说就是GTID还在,事务没了。

双1的影响

为了说明这个问题我们还是要在总结一下双1的功能,如下:
sync_binlog:

这里需要注意的是,sync_binlog还影响了主库发送binlog的时机,这个已经多次提到过了。

innodb_flush_log_at_trx_commit:

8.0中gtid_executed表更新的不同

GTID内存值启动主要的来源

实际上GTID是内存值,一旦重新启动会初始化,初始化的时候主要来自两个地方:

这里实际上我们可以发现5.7和8.0由于gtid_executed表更新时机的变化,导致在初始化的时候也有很大的区别,因为8.0的gtid_executed表几乎包含了大部分的GTID。

最后

显然在上面的分析中,如果B库Crash过后可能导致binlog不完整,因此prepare状态(根据undo标记TRX_UNDO_PREPARED 进行判定,函数trx_resurrect_insert进行恢复事务状态,事务提交的时候trx_undo_set_state_at_prepare函数用于更改undo状态为TRX_UNDO_PREPARED )下的事务可能会回滚,导致了事务丢失,这是可能的,比如例子中就是A:10这个事务丢失了(可以分析xarecover_handlerton函数,核心在于hton->commit_by_xid函数)。

但是gtid_executed表由于clone线程的更新,记录了A:10这个GTID,因此恢复后可能就出现了这种情况。

这里还有、问题,就是要简单证明一下clone线程更新gtid_executed表和sql线程更新数据不在一个事务里面,因为如果在事务事务,理所应该一起回滚或者一起提交,不存在这种问题。下面就是简单的证明,直接拿trx id看看就可以了,主要看其事务ID是否相同。

这里中间3947606,3947608中间少了一个,应该是trx_no,其主要作用是供pruge线程使用,判定哪里事务的undo和del flag可以清理,和trx_id来同一个全局变量(max_trx_id)。

以上,就是这个问题的简单分析,但是实际上还是有一些疑问的,先不做讨论。但是非双1下出现各种稀奇古怪的问题概率大大增加,重要的环境还是要避免使用。

上一篇 下一篇

猜你喜欢

热点阅读