受影响的版本,mysql shell 8.0.30。发起clone,出现死锁
查看mysql错误日志
2024-08-02T07:17:55.570561+08:00 103 [Warning] [MY-013460] [InnoDB] Clone removing all user data for provisioning: Started
按照正常的clone流程,会打印完整的clone信息,但是这里只有开始没有结束,判断是可能有锁等待
使用show processlist
查看,有2个线程在等待
使用show slave status查看,SQL线程在等待退出
查元数据
select * from metadata_locks;
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+------------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+------------------------+-----------------+----------------+
| BACKUP LOCK | NULL | NULL | NULL | 281470428685728 | SHARED | EXPLICIT | GRANTED | sql_backup_lock.cc:100 | 183 | 7 |
| GLOBAL | NULL | NULL | NULL | 281470516200544 | INTENTION_EXCLUSIVE | TRANSACTION | GRANTED | sql_user_table.cc:1855 | 90 | 19 |
| BACKUP LOCK | NULL | NULL | NULL | 281470516200384 | INTENTION_EXCLUSIVE | TRANSACTION | PENDING | sql_user_table.cc:1865 | 90 | 19 |
| TABLE | performance_schema | metadata_locks | NULL | 281470287721952 | SHARED_READ | TRANSACTION | GRANTED | sql_parse.cc:6038 | 387 | 482 |
基本可以确定锁的等待情况
- 线程1(复制处理clone)开始clone,先拿back up锁,然后执行stop slave,等待从库线程关闭,包括sql线程和io线程
- 线程2(sql线程,同步主库)执行grant操作,要拿back up锁,由于被线程1持有,发生锁等待
- 形成死锁:线程1等待线程2,线程2等待线程1
现在要确定grant操作为什么会进入到流程中,因为clone的操作没有这个sql,所以查看mysqlshell的代码
可以看到第1个部分在主库上给指定用户赋予权限,第2个部分开始clone,这样从库在同步时,由于无法保证同步的进度,grant的操作就可能和clone操作同时进行,引起死锁
解决方案,直接在从库kill这个grant即可,不会影响clone和整个流程。
在mysql shell的新版本中,在发起clone前会停止复制,即可规避死锁的错误。如果使用旧版本,在触发clone前需要手动停复制