《MySQL45讲》读书笔记(九):关于元数据锁 online ddl插队问题

此文为极客时间:MySQL实战45讲的元数据锁相关部分问题的思考总结

一、读写锁堵塞

前面在锁这块介绍了元数据锁(MDL 锁)。元数据锁是一种读写锁,他的读读不互斥,读写和写写是互斥的。因此我们参考下面的时序图:

image-20201111201636187

现在等待队列中有四个 session 要获取锁:

  • 由于 sessionA 和 sessionB 都是读操作,读读不互斥,因此两个 session 都持有读锁;
  • sessionA 和 sessionB 还未释放,此时 sessionC 要获取写锁,由于读写互斥,此时 sessionC 发生堵塞;
  • 由于写锁的获取优先级高于读锁,sessionC 的写锁没获取到,后面其他 session 的读锁也无法获取到。此时 sessionD 堵塞;

上面是一个很典型的读写锁堵塞的场景。但是实际测试的时候,会出现 sessionC 和 sessionD 都堵塞了,但是将 sessionA 和 sessionB 提交以后,sessionC 仍然保持堵塞状态,必须等 sessionD 也提交以后,才会继续执行。也就说,sessionD 好像发生了一个插队的现象。

二、锁降级

我们知道 mysql 有一个 online ddl,即 执行 ddl 的时候不会直接锁表导致无法执行其他查询的操作。其实这涉及到一个锁降级的概念。即原本流程是:

  • 拿写锁
  • 做 DDL
  • 释放锁

其他查询语句必须等到 DDL完整的做完这三步以后才能拿到锁,引入锁降级以后,流程变成:

  • 先只拿读锁;
  • 自己先申请内存执行 DDL,先把一些处理做好;
  • 去拿写锁;
  • 真正完成 DDL,替换表结构
  • 释放锁

原本一开始就拿写锁,现在换成了先拿读锁,保证在这期间没有其他 DDL 先执行去修改表,然后自己先把一些读写的过程完成,最后再去拿写锁,把表结构替换上去。相当于原本大家排队买票,轮到了一个人,但是他电话来了,由于他堵着窗口,大家都得等他接完电话才能继续买票。后面大家跟他商量了一些,他接电话的时候先出去,让后面的先继续买票,等他打完电话在回来直接插到最前面。但是这样做的好处在于,避免了修改数据的过程长时间的占用写锁,导致其他 DML 被堵塞。

0%