§ 非阻塞式 DDL

对用户表发起 DDL 操作前,需要先申请 MDL-X 锁,此时如果用户表当前有正在进行中的事务或查询时,会导致 MDL-X 锁的申请被阻塞不能立即获取。由于 MDL-X 锁具有最高优先级,因此当申请 MDL-X 锁被阻塞时,同时还会影响该用户表上的其他新事务、新查询请求,可能会导致这些事务、查询请求继续被阻塞而堆积,可能会严重影响整体业务系统可用性。

下面介绍非阻塞式 DDL 功能的使用方法并解释相关新增选项的作用。

  1. 首先修改锁等待时长选项 lock_wait_timeout,将其设置为 100 秒。
greatsql> SET lock_wait_timeout = 100;
1
  1. 修改选项 lock_ddl_polling_mode 设置,启用该功能。
greatsql> SET lock_ddl_polling_mode = ON;
1

该选项支持在 Session 会话中单独设置,也可以修改 Global 级别设置(修改完 Global 级别设置后,不会对当前 Session 立即生效,只对新建立的 Session 生效)。

  1. 可根据业务特点或需要,修改选项 lock_ddl_polling_runtime,设置每次尝试申请 MDL-X 锁的时长。
greatsql> SET lock_ddl_polling_runtime = 1000;
1
  1. 新增选项
System Variable Name Variable Scope Dynamic Variable Permitted Values Type Default Description
lock_ddl_polling_mode Session YES [ON/OFF] ENUM OFF 是否启用非阻塞式 DDL 特性,默认:不启用
lock_ddl_polling_runtime Session YES [200, 31536000] Integer 1000 非阻塞式 DDL 请求时,每次 DDL 请求尝试持续时长,默认:1000 毫秒(1秒)

原生的 MDL 锁申请是独占式的,也就是在发起 DDL 操作时,需要先申请 MDL-X 锁,如果不能立即申请到,则会被阻塞,直至达到 lock_wait_timeout 选项设定的阈值。

启用非阻塞式 DDL 功能后,在不超过 lock_wait_timeout 定义的时长内,会进行多次申请 MDL-X 锁的尝试,而非原生的独占申请方式,这就可以在多次重试的间隙释放锁资源允许新事务进行。

选项 lock_ddl_polling_runtime 的作用是设置每次尝试申请 MDL-X 锁的最长等待时间。该选项的单位是 ms(毫秒),默认值为 1000,即 1 秒。

  1. 新模式对 DDL 的影响

开启非阻塞式 DDL 功能会导致 DDL 请求申请 MDL-X 锁的时间有所延长,增加 DDL 操作超时失败的概率。

非阻塞式 DDL 功能仅支持 ALTER, OPTIMIZE, TRUNCATE TABLE 这几个 DDL 操作。

  1. 案例

在下面的案例开始之前,已经先修改相关的两个选项,再重新建立三个连接会话:

greatsql> SET GLOBAL lock_ddl_polling_mode = ON;
greatsql> SET GLOBAL lock_ddl_polling_runtime = 200;
1
2
时间线 Session 1 Session 2 Session 3
T1 BEGIN;
SELECT * FROM t WHERE id = 1 FOR SHARE;
发起事务,还未提交
T2 ALTER TABLE t ADD c3 INT UNSIGNED;
对表 t 发起 ALTER TABLE 操作,会被阻塞,提示:
Waiting for table metadata lock
T3 SELECT * FROM t LIMIT 1;
可以返回结果,没有被阻塞

同时也能注意到,在 Session 3 中的 SELECT 查询请求如果多次执行,则每次的响应时长是不一样的,因为 Session 2 中的 ALTER TABLE 请求会多次反复请求 MDL-X 锁,每次最大时长 200ms。

推荐相关阅读:InnoDB and Online DDL (opens new window)

扫码关注微信公众号

greatsql-wx