MySQL:8.0 从库 MTS并发的定时炸弹
作者简介:高鹏,笔名八怪。《深入理解MySQL主从原理》图书作者,同时运营个人公众号“MySQL学习”,持续分享遇到的有趣case以及代码解析!
一、问题描述
8.0.28以下的MTS可能在运行一段时间后出现hang死的情况,大概如下(模拟的):
这个问题因此有一个2的31次方事务后触发的界限,实际上就是int类型的溢出导致,因此为定时炸弹,BUG如下:
- https://bugs.mysql.com/bug.php?id=103636
这个BUG由印风提交,可以看出来跑了很久才触发,着实费劲,感谢大佬,否则真的很难知道为什么。
二、关于slave_preserve_commit_order的实现
实际上本参数主要控制的是从库的提交顺序和主库一致,其实现大概分为两个步骤
- 首先是SQL线程分发事务的时候对顺序进行记录,因为分发是按照主库的binlog的顺序分发的因此可以理解为就是seqnumber的顺序。
- worker线程选择事务执行是无序的,但是在提交的时候就需要保证顺序,这个时候根据SQL线程分发的顺序进行提交即可。
在8.0中主要通过一个全局的Commit_order_manager结构进行记录,其中有2个部分比较重要:
1. 一个全部worker线程信息的vecoter容器,有多少个worker线程容器中就有多少个元素,其中每个元素代表一个worker,叫做node,包含一些重点的成员变量如下:
- m_commit_sequence_nr{NO_SEQUENCE_NR} 提交序列信息
- value_type m_worker_id worker线程的id
- MDL_context *m_mdl_context 包含MDL LOCK信息
- memory::Aligned_atomic m_stage 状态信息
其中m_commit_sequence_nr和m_mdl_context是为唤醒worker线程准备的,这点和5.7不同,5.7中为全部唤醒然后每个worker循环判断,
while (queue_front() != worker->id)