独家揭秘丨 GreatSQL 的 MDL 锁策略升级对执行的影响
独家揭秘丨 GreatSQL 的 MDL 锁策略升级对执行的影响
一、MDL 锁策略介绍
GreatSQL 的 MDL 锁有个策略方法类 MDL_lock_strategy,它根据对象的类型分为了 scope 类型和 object 类型,前者主要用于 GLOBAL, COMMIT, TABLESPACE, BACKUP_LOCK and SCHEMA ,RESOURCE_GROUPS,FOREIGN_KEY,CHECK_CONSTRAINT,BACKUP_TABLES 类型,后者主要用于 DD 表的锁表,本次主要介绍后者的策略原理和策略改变的动机以及对执行的影响。
MDL 以表为单位进行锁表,包括 3 个主要的存储方式:m_fast_path_state 位图、m_granted 队列、m_waiting 队列。
二、MDL 策略级别
mdl 锁可以被申请条件:参考 MDL_lock::can_grant_lock
granted 队列别的线程没有不兼容锁
waiting 队列没有更高等级的锁在等待
具体按照以下的矩阵表来选出 mdl 是否可以被申请,其中 waiting 策略有四个矩阵,这四个矩阵主要是为了防止低优先级的锁等待太久产生锁饥饿,因此按照锁类型的数量必要的时候进行等待锁策略升级,说明见以下。
具体策略矩阵图:(以下+号代表可以被满足,-号代表不能被满足需要进入 waiing 队列等待)
grangted 队列策略:m_granted_incompatible
waiting0 队列策略:m_waiting_incompatible[0],正常申请时候 waiting 队列的矩阵
waiting1 队列策略:m_waiting_incompatible[1],使 SW 优先级比 SRO 低
waiting2 队列策略:m_waiting_incompatible[2],S, SH, SR, SW, SNRW, SRO and SU 优先度比 SNW、SNRW、X 高
waiting3 队列策略:m_waiting_incompatible[3],优先选择 SRO 锁,而非 SW/SWLP 锁。此外,除 SW/SWLP 之外,非“hog”锁优先于“hog”锁。
三、策略升级对实际执行的影响
当有多线程多资源在抢同一张表的锁资源的时候,如果想要低优先级的锁先得到授权,那么可以通过修改系统变量 max_write_lock_count 来实现目的。下面通过 2 个例子来看看修改 max_write_lock_count 如何影响多线程的锁等待动作。
首先创建一张表。
1、max_write_lock_count 设置为 100
SET GLOBAL max_write_lock_count=100;
打开 6 个 session 进行实验。分别敲入以下 SQL 命令。因为 m_piglet_lock_count<max_write_lock_count 因此以下的 6 个 session 都是执行 waiting 的策略 0。
接着第一个 session 执行 commit,观察一下后面几个 session 锁的变化,可以看到最后一个 session 的 SW 锁因为实行的是策略 0 因此 commit 之后按照 SW 优先度比 SRO 高获取到了 SW 锁。
2、max_write_lock_count 设置为 1
SET GLOBAL max_write_lock_count=1;
这里在执行完 session4 的时候因为 m_piglet_lock_count>=max_write_lock_count,因此进行了一次 waiting 策略升级,升级为了策略 1。
接着第一个 session 执行 commit 释放 SHARED_WRITE 锁,可以看到最后一个 session 的 SW 锁应该在策略 1 优先度比 SRO 低,因此还处于等待状态。而在之前第一个例子里,因为实行的是策略 0 因此 commit 之后最后一个 session 因为优先度比 SRO 高因此获取到了 SW 锁。
在 session5 的 SRO 获取到锁以后,因为已经没有 SRO 锁在等待了,因此进行了一次 waiting 策略降级,重新降级为了 0。
用命令查看一下锁状态
3、锁改变策略时机
锁唤醒时机,参考 MDL_lock::reschedule_waiters:
可以看到上面的例子就是在 commit 以后执行了锁唤醒才导致了策略升级,于是产生了跟第一个例子不同的结果。
四、总结
实际生产中如果在多个线程抢同一张表的锁资源的时候,如果想要低优先级的锁优先获得锁,可以尝试修改系统变量 max_write_lock_count,改小可以防止锁饥饿,但是可能会影响别的线程正在执行的业务,因此也要谨慎使用。当然如果想要高优先级锁先获得锁也可以改大 max_write_lock_count 值,看具体业务需求。
版权声明: 本文为 InfoQ 作者【GreatSQL】的原创文章。
原文链接:【http://xie.infoq.cn/article/2ad9ef84d821d217c4c3f631b】。文章转载请联系作者。
评论