本文介绍了在PolarDB MySQL版中执行DDL操作时提示“获取不到MDL锁”的解决方法。
问题现象
在PolarDB MySQL版数据库中执行DDL操作时提示获取不到MDL锁,报错信息如下:
ERROR HY000: Fail to get MDL on replica during DDL synchronize
ERROR HY000: Fail to get table lock on replica; you can 'set polar_support_mdl_sync_preemption = ON' and try restarting transaction
问题原因
PolarDB MySQL版的只读节点上存在未结束的查询或未提交的事务。
解决方案
您可以选择以下任一方案执行,以解决您目前所遇到的问题:
建议您可以直接使用第一种方案。为只读节点开启抢占式DDL功能来解决当前问题。具体操作,请参见抢占式DDL。
提交(commit)或回滚(rollback)只读节点上未提交的事务。
在只读节点上开启polar_slave_work_on_nonblock_mdl_mode参数,防止只读节点上未提交的长事务阻塞DDL操作。具体操作,请参见防止只读节点上长事务阻塞DDL操作。
您可以登录PolarDB控制台,前往集群的 页面,在会话管理页签中检查是否存在异常会话。若发现异常会话,请单击异常区域内的查看详情以获取异常会话的具体信息。此时,建议您结束这些长时间未提交的事务的会话。对于其他异常会话,请根据实际业务场景进行优化或结束。更多信息,请参见会话管理。
您可以通过集群中的Polar Performance Schema功能,查询目标表的MDL锁状态,并终止只读节点上未提交事务的相关线程,以解决您的问题。具体操作步骤如下:
查看集群中Polar Performance Schema功能的状态。您可以通过以下两种方式来查看:
您可以登录PolarDB控制台,前往集群的 页面查看参数
loose_polar_performance_schema
的值。集群参数在控制台上都已加上MySQL配置文件的兼容性前缀loose_。
执行以下SQL:
SHOW VARIABLES LIKE 'polar_performance_schema';
+--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | polar_performance_schema | ON | +--------------------------+-------+
根据参数的开启与关闭状态,处理方式将有所不同。
开启(ON)
您可以通过
performance_schema.metadata_locks
来查询目标表上MDL锁状态,来确定是否有事务未提交。然后使用kill
命令终止未提交事务的相关线程。使用Hint语法指定只读节点执行以下SQL查询目标表上MDL锁状态。
/*force_node='pi-bp10k7631d6k3****'*/ SELECT t.PROCESSLIST_ID, m.OBJECT_TYPE, m.OBJECT_SCHEMA, m.OBJECT_NAME, m.LOCK_TYPE, m.LOCK_DURATION, m.LOCK_STATUS FROM performance_schema.metadata_locks m LEFT JOIN performance_schema.threads t ON m.owner_thread_id=t.thread_id;
显示结果如下:
从上图可以看到,当前
test01/t1
这个表上,有一个大查询或者未提交的事务,持有了LOCK_TYPE
为SHARED_READ
的锁。同时,当前test/t1
表上有一个LOCK_TYPE
为EXCLUSIVE
的锁处于PENGING
状态。使用Hint语法指定只读节点执行
kill
命令终止连接对应的线程即可。说明如果当前只读节点上未提交的事务非常重要,建议不要直接使用
kill
命令终止当前事务,请耐心等待此事务结束后,再进行DDL操作。如果使用
kill
命令无法终止线程,导致线程ID不存在或者出现如下错误,请联系我们处理。ERROR 1094 (HY000): Unknown thread id: xxx
/*force_node='pi-bp10k7631d6k3****'*/ kill 536976473;
关闭(OFF)
您可以通过
information_schema.innodb_trx
来查询目标表上MDL锁状态,来确定是否有事务未提交。然后使用kill
命令终止未提交事务的相关线程。使用Hint语法指定只读节点执行以下SQL查询
information_schema.innodb_trx
表上MDL锁状态。/*force_node='pi-bp10k7631d6k3****'*/ SELECT * FROM information_schema.innodb_trx\G
根据结果判断是大查询还是大事务导致的:
大查询导致的DDL执行失败显示结果如下:
从上图可以看到,当前表
t1
上面存在一个大查询,说明当前的连接持有了表t1
的MDL锁。大事务导致的DDL执行失败显示结果如下:
从上图可以看到,有一个未提交的事务537247177,由于
trx_query
字段为空,无法准确判断当前事务持有了当前表的MDL锁。此时您可以根据trx_started
字段进行处理,如果trx_started
字段的时间和当前时间的差距很大,大概率是当前事务537247177持有了MDL锁。
使用Hint语法指定只读节点执行
kill
命令终止连接对应的trx_mysql_thread_id
线程即可。/*force_node='pi-bp10k7631d6k3****'*/ kill 537247177
联系我们
若您对DDL操作有任何疑问,可通过钉钉搜索群号入群咨询。您可以直接@群内专家,并附上您要咨询的问题;同时群内也有PolarDB MySQL版小助手24*7小时在线回答您的问题。钉钉群号:15375044501。
更多信息
云原生数据库PolarDB中DDL操作的过程如下:
在DDL操作的不同阶段,如果需要变更表结构,则在变更前,主节点先获取MDL锁,然后写入一条Redo日志。
只读节点解析到此Redo日志时,会尝试获取同一个表中的MDL锁。然后有下列两种情况:
获取成功,进入下一步。
获取失败,只读节点反馈给主节点。
主节点等待所有只读节点同步到最新的复制位点。在一定时间内,主节点会判断所有只读节点是否都解析到了此Redo日志以及是否加锁成功。然后有下列两种情况:
所有只读节点同步到最新的复制位点,DDL成功。
某些只读节点未同步到最新的复制位点,回滚DDL并报错。此时报错又分为两种情况:一种是等待同步超时的报错;另一种是本文中加锁失败的报错,而某些只读节点加锁失败的主要原因是只读节点存在未结束的查询或者未提交的事务。