非阻塞DDL

RDS MySQL支持非阻塞DDL(Non blocking DDL)功能,规避了DDL执行过程中因MDL锁长时间获取不成功导致的会话阻塞和连接堆积,提升DDL过程中实例的稳定性和可用性。

功能说明

背景:MySQL中,DDL操作需要获取目标表的MDL-X锁,以确保元数据一致性。然而,当表上存在未提交事务或长查询时,DDL线程会因无法立即获取锁而进入等待状态(pending)。由于MDL-X锁具有最高优先级,pending状态下的MDL-X锁会阻塞目标表后续的所有访问,引发会话阻塞、连接堆积和响应延迟等问题,严重时可能导致整个业务系统不可用。

简介:RDS MySQL的非阻塞DDL通过修改DDL线程获取和等待MDL锁的策略,将“一次性长等待”改为“间歇性短等待”。在等待间歇中,DDL线程会释放对MDL-X的请求,新会话允许访问目标表,避免了DDL线程长时间阻塞其他会话对目标表的访问。

适用范围

  • 仅当数据库大版本为MySQL 8.0且内核小版本大于等于20250531时,才能开启非阻塞DDL功能。当版本不符合要求时,可以升级升级内核小版本数据库大版本

  • 使用非阻塞DDL功能时,有以下限制:

    • 当前仅支持ALTER TABLECREATE INDEXDROP INDEX操作。OPTIMIZE TABLE操作可以使用ALTER TABLE ... ENGINE = InnoDB代替。

    • 主节点同步至备节点或只读实例时,备节点或只读实例上本功能不生效。

    • 开启本功能会降低DDL的优先级,因此无法获取MDL锁导致DDL失败的概率会增大。

参数管理

参数说明

您可以通过loose_rds_nonblock_ddl_retry_intervalloose_rds_nonblock_ddl_lock_wait_timeout参数来控制和调整非阻塞DDL功能。开启非阻塞DDL功能后,DDL线程会间歇性多次尝试获取MDL锁,获取失败则释放MDL请求并陷入等待。

参数名称

说明

loose_rds_nonblock_ddl_retry_interval

  • 描述:DDL线程获取MDL锁超时重试的时间间隔。

  • 参数范围:会话级别。

  • 数据类型:Integer

  • 默认值:0(表示非阻塞DDL功能不生效)。

  • 取值范围:0~31536000,单位:秒。

  • 是否需要重启实例:否。

loose_rds_nonblock_ddl_lock_wait_timeout

  • 描述:DDL 线程间歇性获取MDL锁的超时时间。

  • 参数范围:会话级别。

  • 数据类型:Integer

  • 默认值:1

  • 取值范围:1~31536000,单位:秒。

  • 是否需要重启实例:否。

修改参数

  1. 访问RDS实例列表,在上方选择地域,然后单击目标实例ID。

  2. 在左侧导航栏中单击参数设置

  3. 可修改参数页签内搜索待修改参数,并配置参数值。

  4. 单击确定,然后单击提交参数,并在弹出的窗口中选择生效的时间段。

功能效果

测试方法

本文采用sysbench工具模拟数据库实例上的数据访问,对比开启与关闭非阻塞DDL功能时,执行DDL对业务的影响。具体测试步骤如下:

  1. 使用sysbench构建表并插入数据。

    sysbench oltp_read_write --db-ps-mode=auto --percentile=95 --mysql-host=$HOST --mysql-port=$PORT --mysql-user=$USER --mysql-db=$DB --tables=1 --table-size=50 --threads=16 prepare
  2. 启动sysbench压力测试模拟在线业务。

    sysbench oltp_read_write --db-ps-mode=auto --percentile=95 --mysql-host=$HOST --mysql-port=$PORT --mysql-user=$USER --mysql-db=$DB --tables=1 --table-size=50 --threads=16 --report-interval=1 --time=100 run
  3. 启动一个会话,在待执行的目标表上开启长事务,以阻塞后续的 DDL 操作。

    SELECT SLEEP(60) FROM sbtest1 LIMIT 1;
  4. 启动另一个会话,在关闭非阻塞DDL功能的情况下执行如下DDL操作,观察TPS变化。

    ALTER TABLE sbtest1 ENGINE = InnoDB;
    -- 预期:该DDL线程由于无法获取MDL锁被阻塞。
  5. 开启非阻塞DDL功能:设置loose_rds_nonblock_ddl_retry_interval参数值为 6,loose_rds_nonblock_ddl_lock_wait_timeout 参数值为1。执行相同的DDL操作,观察TPS变化。

    ALTER TABLE sbtest1 ENGINE = InnoDB;
    -- 预期:该DDL线程可以获取MDL锁,不会完全被阻塞

测试结果

  • 关闭非阻塞DDL功能时,DDL线程无法获取MDL锁,会话被完全阻塞。

  • 开启非阻塞DDL功能后,DDL线程可以间歇性地获取MDL锁,会话不会被完全阻塞,系统稳定性得到保障。

image.png

image