TDSQL Boundless 抢占式 DDL

TDSQL Boundless 提供抢占式 DDL 功能,用于解决分布式场景下, DDL 操作因其他节点上的长查询事务持有 MDL-S 锁而长时间等待甚至超时失败的问题。

相关产品
TDSQL Boundless 产品页,含版本规格、价格与购买入口。

一、功能概述

开启抢占式 DDL 后,当 DDL 操作在目标节点等待 MDL-X 锁超过指定时间时,系统将主动终止阻塞 MDL-X 锁获取的长查询的会话,确保 DDL 操作能够顺利完成。

二、TDSQL Boundless 分布式架构下的 DDL 锁协调

TDSQL Boundless 采用分布式架构,每个 SQLEngine 节点均具备独立的读写能力。当某个节点执行 DDL 操作时,需要在以下两个层面获取锁:

1. 本节点 MDL 锁: DDL 需要在发起节点获取目标表的 MDL-X 锁,与本节点上的活跃事务互斥。

2. 全局对象锁: DDL 需要通过元数据服务(TDMC)获取全局对象锁,确保同一时间只有一个节点能修改表结构,防止跨节点 DDL 冲突。

三、问题现象

在同一节点上,如果存在对目标表的长查询事务,这些会话会持有该表的 MDL-S 锁。DDL 操作需要获取 MDL-X 锁,两者互斥,导致 DDL 被阻塞。如果长事务在锁等待超时时间内未结束,DDL 将执行失败。

典型报错:

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

在未开启抢占式 DDL 的情况下,处理此类问题通常需要 DBA 手动定位并终止持锁会话,操作流程繁琐且响应不及时。

四、抢占式 DDL 的解决思路

抢占式 DDL 提供了一种自动化的解决方案:当 DDL 等待 MDL 锁超过指定时间后,系统将自动终止阻塞 DDL 的长查询的会话,释放 MDL 锁资源,使 DDL 操作能够继续执行。相比手动干预,这种方式响应更快、操作更可靠。

五、注意事项

·业务影响: 开启抢占式 DDL 后,阻塞 DDL 的会话将被系统强制终止,会话上未提交的事务将被回滚。请评估业务对事务中断的容忍度。

·建议在低峰期使用: 尽管抢占式 DDL 能自动处理锁冲突,仍建议在业务低峰期执行 DDL 变更,以减少对正常业务的影响。

六、参数说明

通过以下参数控制抢占式 DDL 的行为,可在控制台的参数配置页面或通过 SQL 命令进行设置。

参数 级别 说明 取值范围 默认值
tdsql_ddl_block_mode Session 控制普通线程(normal)DDL 锁获取行为,设置为 preemptive 时启用抢占式 DDL 逻辑 preemptivenonblockdefault preemptive
tdsql_ddl_recovery_block_mode Global 控制恢复线程(recovery)DDL 锁获取行为,设置为 preemptive 时启用抢占式 DDL 逻辑;仅 GLOBAL 级别设置生效,SESSION 级别设置无效 preemptivenonblockdefault preemptive
tdsql_ddl_preempt_after_wait_seconds Session 抢占式 DDL 等待 MDL‑X 锁的容忍时间,超过该时间后自动触发锁抢占流程。单位:秒 1 ~ 31536000 50

七、使用方法

1. 开启抢占式 DDL。

在执行 DDL 的会话中开启功能:

SET tdsql_ddl_block_mode = 'preemptive';– tdsql_ddl_block_mode参数的默认值即为 'preemptive'

2. (可选)调整抢占等待时间。

例如设置为5秒:

SET tdsql_ddl_preempt_after_wait_seconds = 5;

3. (可选)配置恢复线程抢占式 DDL。

SET GLOBAL tdsql_ddl_recovery_block_mode = 'preemptive';

4. 执行 DDL 操作。

ALTER TABLE orders ADD COLUMN remark VARCHAR(255);

如果当前节点上存在长查询事务阻塞了该表的 MDL 锁,系统将在等待指定时间后自动终止阻塞会话,DDL 继续执行直至完成。

八、准备工作

创建测试表并插入数据:

CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(50));INSERT INTO t1 VALUES (1, 'Alice'), (2, 'Bob');

九、未开启抢占式 DDL

会话1(模拟长查询事务):

BEGIN;SELECT * FROM t1;– 事务未提交,持有 t1 的 MDL 共享读锁

会话2(执行 DDL):

ALTER TABLE t1 ADD COLUMN age INT;– 等待 MDL 排他锁…– 超时后报错:– ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

结果: DDL 执行失败,需要 DBA 手动通过 performance_schema.metadata_locks 定位持锁会话。

十、开启抢占式 DDL

会话1(模拟长查询事务):

BEGIN;SELECT * FROM t1;– 事务未提交,持有 t1 的 MDL 共享读锁

会话2(开启抢占式 DDL 并执行):

SET tdsql_ddl_block_mode = 'preemptive';SET tdsql_ddl_preempt_after_wait_seconds = 5;ALTER TABLE t1 ADD COLUMN age INT;– 等待 5 秒后,系统自动触发抢占并终止阻塞会话Query OK, 0 rows affected (5.067 sec)Records: 0 Duplicates: 0 Warnings: 0

会话1的变化:

SELECT * FROM t1;ERROR 2013 (HY000): Lost connection to MySQL server during query

结果: DDL 执行成功。会话1被终止,事务被回滚,后续操作需重新发起。

十一、排查与诊断

当 DDL 操作遇到 MDL 锁阻塞时,你也可以通过以下方式手动排查,作为抢占式 DDL 的补充手段:

1. 查看 MDL 锁持有情况:

SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_NAME = 't1';

2. 定位持锁会话并参考 PROCESSLIST_ID 手动终止持锁会话:

SELECT ml.OBJECT_NAME, ml.LOCK_TYPE, ml.LOCK_STATUS, t.PROCESSLIST_ID, t.PROCESSLIST_INFOFROM performance_schema.metadata_locks mlJOIN performance_schema.threads t ON ml.OWNER_THREAD_ID = t.THREAD_IDWHERE ml.OBJECT_NAME = 't1' AND ml.LOCK_STATUS = 'GRANTED';

注意:说明:

注意:在分布式场景下,如果 DDL 报错 ERROR 8542 … Acquire object lock … wait timeout,表明 DDL 被其他节点的 DDL 通过全局对象锁阻塞,此场景属于 DDL-DDL 冲突,需等待另一个 DDL 完成,抢占式 DDL 不适用于此场景。

十二、相关文档

·Online DDL 说明

·锁机制解析与问题排查实践

赞 (0)
上一篇 4天前
下一篇 4天前