PolarDB新增非阻塞DDL(Nonblock DDL)功能。Nonblock DDL规避了执行DDL过程中MDL锁长时间获取不成功导致的连接堆积和阻塞,有效地解决了DDL导致的锁表问题。
背景信息
用户在执行DDL操作的时候,若目标表存在未提交的长事务或大查询,DDL将持续等待获取MDL-X锁。在PolarDB中由于MDL-X锁具有最高优先级,DDL在等待MDL-X锁的过程中,将阻塞目标表上所有的新事务,这将导致业务连接的堆积和阻塞,可能会造成整个业务系统崩溃的严重后果。PolarDB提供的Nonblock DDL功能,可以保证即使在无法获得MDL-X锁的情况下,依然允许新事务进入目标表,从而保证整个业务系统的稳定。
前提条件
PolarDB MySQL版集群需满足如下条件之一:
PolarDB MySQL版8.0.1版本且Revision version为8.0.1.1.29及以上。
PolarDB MySQL版8.0.2版本且Revision version为8.0.2.2.12及以上。
您可以通过查询版本号来确认集群版本。
注意事项
开启Nonblock DDL功能会导致DDL的优先级降低,同时因MDL锁获取失败从而导致执行DDL的失败概率也会相应增大。
使用限制
PolarDB MySQL版8.0.1版本且Revision version为8.0.1.1.29及以上,以及8.0.2.2.12版本:
仅ALTER TABLE语句支持Nonblock DDL功能,应用于
ALTER TABLE table_name ADD INDEX index_name ( `column1`, `column2`, `column3` )
语句效果更佳。对于在InnoDB引擎上创建的表,需要使用
ALTER TABLE table_name engine=innodb
命令来代替OPTIMIZE TABLE table_name
命令进行碎片整理。
PolarDB MySQL版8.0.2版本且Revision version为8.0.2.2.13及以上:
ALTER TABLE、OPTIMIZE TABLE和TRUNCATE TABLE语句支持Nonblock DDL功能。
使用方法
您可以先通过loose_polar_nonblock_ddl_mode参数开启Nonblock DDL功能,并通过loose_polar_nonblock_ddl_retry_times参数设置获取MDL-X锁超时重试的次数、loose_polar_nonblock_ddl_retry_interval参数设置获取MDL-X锁超时重试的时间间隔、loose_polar_nonblock_ddl_lock_wait_timeout参数设置获取MDL-X锁超时的时间。具体操作请参见设置集群参数和节点参数。参数说明如下:
参数 | 级别 | 说明 |
loose_polar_nonblock_ddl_mode | Session | Nonblock DDL功能开关。取值范围如下:
|
loose_polar_nonblock_ddl_retry_times | Session | 设置获取MDL-X锁超时重试的次数。取值范围:0~31536000。默认值为0(由参数 说明 该参数值建议设置为4194304。 |
loose_polar_nonblock_ddl_retry_interval | Session | 设置获取MDL-X锁超时重试的时间间隔。取值范围:1~31536000。单位为秒。默认值为6。 |
loose_polar_nonblock_ddl_lock_wait_timeout | Session | 设置获取MDL-X锁超时的时间。取值范围:1~31536000。单位为秒。默认值为1。 |
性能对比
本文档对比了开启和关闭Nonblock DDL功能对业务的影响情况,同时与使用外部工具gh-ost进行表结构变更也进行了性能对比。
测试工具
SysBench是一个跨平台且支持多线程的模块化基准测试工具,用于评估系统在运行高负载的数据库时相关核心参数的性能表现。使用SysBench是为了绕过复杂的数据库基准设置,甚至在没有安装数据库的前提下,快速了解数据库系统的性能。关于如何使用SysBench,请参见性能测试方法(OLTP)。
测试环境
一个规格为8核64 GB的标准版PolarDB MySQL版8.0版本的集群。
测试方法
使用SysBench创建1个测试表
sbtest1
,并插入1000000行数据。./oltp_read_write.lua --mysql-host="集群地址" --mysql-port=“端口号” --mysql-user=“用户名” --mysql-password=“用户密码” --mysql-db="sbtest" --tables=1 --table-size=1000000 --report-interval=1 --percentile=99 --threads=8 --time=6000 prepare
通过SysBench中的
oltp_read_write.lua
模拟用户业务。./oltp_read_write.lua --mysql-host="集群地址" --mysql-port=“端口号” --mysql-user=“用户名” --mysql-password=“用户密码” --mysql-db="sbtest" --tables=1 --table-size=1000000 --report-interval=1 --percentile=99 --threads=8 --time=6000 run
在目标表
sbtest1
上开启一个事务但不提交,该事务将持有目标表sbtest1
的MDL锁。/* session 1 */ begin; select * from sbtest1;
在新会话中,开启和关闭Nonblock DDL功能的条件下,分别对表
sbtest1
进行加列操作,观察TPS的变化情况。/* session 2 */ alter table sbtest1 add column d int;
使用gh-ost工具进行加列操作,观察TPS的变化情况(开启Binlog)。
./gh-ost --assume-rbr --user="用户名" --password="用户密码" --host="集群地址" --port="端口号" --database="sbtest" --table="sbtest1" --alter="ADD COLUMN d INT" --allow-on-master --aliyun-rds --initially-drop-old-table --initially-drop-ghost-table --execute;
测试结果
关闭Nonblock DDL,TPS持续跌零。默认超时时间为31536000,严重影响用户业务。
开启Nonblock DDL,TPS周期性下降,但未跌零。对用户业务影响较小,能保证业务系统的稳定。
使用gh-ost进行表结构无锁变更,TPS周期性跌零。对用户业务影响很大,这是cut-over阶段短暂锁表造成的。
Nonblock DDL与gh-ost工具性能对比
开启Nonblock DDL并使用传统的加列方式(INSTANT、INPLACE、COPY)与使用gh-ost工具分别对100万行数据的表进行加列操作的性能对比如下:
在无负载的情况下,通过下图可以看出开启Nonblock DDL并使用传统的加列方式(INSTANT、INPLACE、COPY)比使用gh-ost工具耗时更少。
使用SysBench的oltp_read_write模拟业务负载,通过下图可以看出开启Nonblock DDL并使用传统的加列方式(INSTANT、INPLACE、COPY)比使用gh-ost工具耗时更少。
测试结论
Nonblock DDL功能在DDL执行期间能更好的规避新事务阻塞、TPS跌零等问题,从而尽可能的保证业务系统的稳定性。同时,能够提供更高效的DDL变更能力。
联系我们
若您对DDL操作有任何疑问,请联系我们。