暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PolarDB ·引擎特性· DDL中MDL锁的优化和演进(三)

Z 2023-06-24
264

3. Preemptive DDL (饥饿问题)

3.1 功能概述

上文非阻塞DDL解决了DDL获取MDL锁阻塞导致的业务雪崩问题,但是如果DDL迟迟无法获取MDL锁,会导致DDL执行频繁失败。目前线上值班偶尔会遇到由于RO上面存在大查询、长事务导致的DDL执行失败问题,并返回错误ERROR 8007 (HY000): Fail to get MDL on replica during DDL synchronize。由于此报错与PolarDB共享存储的架构相关,与传统MySQL不一致,用户经常会一头雾水,无从下手。当前已有官方文档(执行DDL操作提示“获取不到MDL锁”)介绍这类问题的解决方案,用户可以根据此文档找到只读节点上持有表MDL锁的事务,手动进行Kill,来保证DDL同步MDL锁的成功。但是这种方式在部分场景下依然非常晦涩,一方面用户进行kill操作的时间窗口有限(当前同步MDL锁超时时间为50秒,可通过loose_replica_lock_wait_timeout进行调整),另一方面随着PolarDB上面客户不断增多,出现了许多10+个只读节点的集群,手动kill操作显得狼狈且低效,为此我们提供了抢占式DDL功能。

当只读节点通过物理复制,解析到当前表上有DDL操作时,只读节点会尝试获取表的MDL锁。如果此时表上存在大查询或长事务时,开启Preemptive DDL后(用户文档),如果只读节点在预期时间内无法获得MDL锁,便会尝试kill掉占有MDL锁的线程,从而保证MDL锁同步的成功,解决DDL的饥饿问题。

3.2 测试效果

可以通过设置参数loose_polar_support_mdl_sync_preemption为ON来打开抢占式DDL功能,下面给出DDL同步MDL锁被只读节点长事务堵塞时,开启和关闭抢占式DDL的实验效果。

  • 关闭抢占式DDL功能
  1. 在只读节点上查询test.t1:
mysql> use test
Database changed
#大查询,执行100s
mysql> select sleep(100) from t1;
  1. 在主节点进行加列操作,被block,执行失败:
mysql > alter table t1 add column c int;
ERROR 8007 (HY000): Fail to get MDL on replica during DDL synchronize


由于只读节点存在大查询,同步MDL锁失败,DDL执行失败,并回滚。

  • 开启抢占式DDL功能
  1. 在只读节点上查询test.t1:
mysql> use test
Database changed
#大查询,执行100s
mysql> select sleep(100) from t1;
  1. 在主节点进行加列操作操作,被block,等待一段时间,发生抢占,执行成功:
mysql> alter table t1 add column c int;
Query OK, 0 rows affected (11.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

img

开启抢占式DDL功能后,加列操作完成,同时可以看到只读节点(右图),大查询连接已经断开。




「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论