安全数据库GreatDB作为万里数据库自主研发的一款核心数据库产品,于2023年底首批通过安全可靠测评,可根据用户需求选择集中式或分布式部署。
GreatDB拥有哪些特性?解决了用户哪些痛点难题?
基于此,万里数据库悉心推出【产品解读】专栏,将从非阻塞式DDL、读写分离、备份方式等多个维度深入阐述GreatDB产品特性,帮您了解并用好GreatDB~
01
痛点说明
运维MySQL开源数据库的DBA,一般都有被MDL锁阻塞的经历。
DDL会申请操作对象的独占MDL锁,如果不能立即获得独占MDL锁,DDL的锁申请会进入该对象MDL的锁申请队列,后续所有该对象上的操作由于也要先申请MDL锁。
因此,这些锁申请也会进入到锁申请队列,排在DDL锁申请之后,导致该对象上的所有后续操作(包括DML操作和select)都被阻塞。
02
万里数据库GreatDB解决方案
针对DBA的上述痛点,GreatDB给出了自己的解决方案,增加了非阻塞式DDL功能。
在 lock_wait_timeout 定义时间内,DDL操作的会话间歇性申请独占MDL锁,在多次申请的间隙(200ms)会释放锁资源,允许新事务获取该对象的DML锁,从而提高数据库并发性。
GreatDB为非阻塞式DDL功能新增2个会话变量:
•lock_ddl_polling_mode
控制是否启用非阻塞式DDL特性,默认值:OFF,Global和Session级变量,可动态修改;
•lock_ddl_polling_runtime
每次尝试获取独占MDL锁的持续时长,单位:毫秒,默认值:1000 ;Global和Session级变量,可动态修改。
03
实验验证
在MySQL8.0.32和GreatDB6.1.1下,参数lock_wait_timeout都设置为600秒,使用DDL操作drop index构造DDL锁请求,观察MySQL的表现,并对比GreatDB非阻塞式DDL的表现。
3.1 MySQL的DDL锁表现
会话A | 会话B | 会话C |
mysql> begin; | ||
mysql> alter table test1 add index idx_k(k); | ||
mysql> select count(*) from test1; | ||
<<DDL语句中断或超时退出 | ||
<<会话获取MDL锁 |
MySQL会话C被阻塞的分析
•会话 B 的 DDL 被阻塞:
○DDL需要独占MDL锁,但会话A的未提交事务仍持有共享MDL锁。
○会话B进入MDL锁等待队列,直到会话A释放共享锁。
•会话 C 的 SELECT 阻塞:
○MySQL的MDL锁机制采用写锁优先策略:当有排他锁请求等待时,后续共享锁请求需等待独占锁获取后释放。
○会话C的SELECT需要共享MDL锁,但此时会话B的独占锁请求已处于等待队列中。根据锁优先级,会话C会被阻塞,直到会话B释放MDL锁。
3.2 GreatDB非阻塞式DDL表现
修改数据库的全局变量,启用非阻塞DDL功能。
##--启用非阻塞式DDL特性 |
会话1 | 会话2 | 会话3 |
greatdb> begin; | ||
greatdb> alter table test1 add index idx_k(k); | ||
greatdb> select count(*) from test1; |
GreatDB会话C未被阻塞的分析
会话B的DDL被阻塞:
DDL申请独占MDL锁,但会话A的未提交事务仍持有共享MDL锁,无法立即获得独占MDL锁。
会话B进入表test1的MDL锁等待队列,设置超时时间lock_ddl_polling_runtime(100ms),超时后退出,等待200ms后,再次进入锁等待队列,循环执行。
检查总等待时间,未超过 lock_wait_timeout时,继续上述循环,否则DDL超时退出。
会话 C 的 SELECT 阻塞:
会话C的SELECT需共享MDL锁,但此时会话B的DDL排他锁请求可能处于以下情况:
在等待队列中。由于会话B的申请间歇性退出等待队列,会话C获取共享MDL锁,完成select操作;
不在等待队列中(在200ms的等待时间),会话C获取共享MDL锁,完成select操作。
04
总 结
GreatDB通过非阻塞式 DDL 功能,使DDL操作的会话间歇性申请独占MDL锁,在申请的间隙会释放锁资源,允许新事务获取该对象的DML锁,从而完成MDL和select操作,彻底解决了困扰DBA的MDL锁阻塞问题。







