一、故障表现
MySQL高可用从库复制延迟持续升高,从库的executed_gtid集合不变化。
二、故障信息
processlist如下图
备份进程如下图:
三、故障原因
看这个图的48、49、18747763这三个进程即可。以下按时间顺序描述:
1、session 48 开始回放但未进入提交阶段;
2、session 49 先提交,持有了表的commit锁,但需要等待session 48的事务先提交,进入waiting for preceding transaction to commit的状态,这里是因为slave_preserve_commit_order=1, 事务保序回放;
3、session 18747763 备份进程加锁,flush table with read lock先拿到全局读锁GLOBAL:S,下一步是拿全局COMMIT锁,这个全局锁的获取 被session 49的commit锁堵塞,进入waiting for commit状态;
4、session 48 应用Xid_event提交事务,尝试获取commit:IX锁,但是由于"COMMIT:IX和COMMIT:S的互斥性",被session 18747763堵塞;
所以就形成了 49等待48、48等待18747763、18747763等待49 的死锁。参考下图:
四、临时解决方案
这种故障表现具备一定的偶然性,因此可以:
kill掉session 18747763备份进程的全局锁的获取,让MTS恢复正常;手工重新发起备份
涉及范围:5.7 & 8.0
五、长期解决方案
1、slave_preserve_commit_order=0规避,不建议;
2、set global slave_parallel_workers=0;stop slave;start slave; 关掉并行复制、或者直接stop slave sql_thread; 备份完再set回来(管控实现)
六、一些MDL信息补充
1、MDL实现,可参考 http://mysql.taobao.org/monthly/2015/11/04/
2、FTWRL与DML分别涉及的MDL锁,可参考下图(可能因版本更新不完全准确)。
FTWRL获取两个锁 MDL::global read lock 和MDL::global commit lock。
DML事务执行中获取MDL_key::GLOBAL IX锁;在事务提交前,会先请求MDL_key::COMMIT IX锁。
七、一些疑问回答
1、为什么xtrabackup没有主动停止,备份命令中的--ftwrl-wait-query-type=all --ftwrl-wait-timeout=180 没有生效?
>> 这两个参数是ftwrl加锁前的检查,检查没有超时进程,才开始执行Flush table with read lock
2、为什么xtrabackup没有kill掉并行复制的慢查询,备份命令中的--kill-long-queries-timeout=20 --kill-long-query-type=all 没有生效?
>> xtrabackup选择杀掉的线程时,不处理从库的MTS线程。如下参数说明参考。
3、为什么lock_wait_timeout=1800没有生效,全局锁持续了几千秒 没有主动结束?
>> xtrabackup执行全量备份时会执行SET SESSION lock_wait_timeout=31536000
>> lock_wait_timeout本身 对mdl锁是生效的