一 简介 
  上一篇文章 《MetaData Lock 之一》  简单的介绍了MySQL 引入MDL 的前因后果,本文深入了解MDL的实现原理和运行机制。
二 MDL 的类型
  metadata lock也是一种锁。每个metadata lock都会定义锁住的对象,锁的持有时间和锁的类型。
2.1 按照对象/范围划分

属性 含义 范围/对象
GLOBAL 全局锁 范围
COMMIT 提交保护锁 范围
SCHEMA 库锁 对象
TABLE 表锁 对象
FUNCTION 函数锁 对象
PROCEDURE 存储过程锁 对象
TRIGGER 触发器锁 对象
EVENT 事件锁 对象

MDL按锁住的对象来分类,可以分为global,commit,schema, table, function,procedure,trigger,event,这些对象发生锁等待时,我们在show processlist可以分别看到如下等待信息。

  1. Waiting for global read lock
  2. Waiting for commit lock
  3. Waiting for schema metadata lock
  4. Waiting for table metadata lock
  5. Waiting for stored function metadata lock
  6. Waiting for stored procedure metadata lock
  7. Waiting for trigger metadata lock
  8. Waiting for event metadata lock

2.2 按照锁的持有时间

属性 含义
MDL_STATEMENT 从语句开始执行时获取,到语句执行结束时释放。
MDL_TRANSACTION 在一个事务中涉及所有表获取MDL,一直到事务commit或者rollback(线程中终清理)才释放。
MDL_EXPLICIT 需要MDL_context::release_lock()显式释放。
语句或者事务结束,也仍然持有,如
Lock table, flush .. with lock语句等。

2.3 按照操作的对象

属性 含义 事例
MDL_INTENTION_EXCLUSIVE(IX) 意向排他锁用于global和commit的加锁。 truncate table t1;
insert into t1 values(3,'abcde');会加如下锁(GLOBAL,MDL_STATEMENT,MDL_INTENTION_EXCLUSIVE)                            (SCHEMA,MDL_TRANSACTION,MDL_INTENTION_EXCLUSIVE)

MDL_SHARED(S) 只访问元数据 比如表结构,不访问数据。 set golbal_read_only =on 加锁
(GLOBAL,MDL_EXPLICIT,MDL_SHARED)
MDL_SHARED_HIGH_PRIO(SH) 用于访问information_scheam表,不涉及数据。 select * from information_schema.tables;
show create table xx; desc xxx;会加如下锁:
(TABLE,MDL_TRANSACTION,MDL_SHARED_HIGH_PRIO)
MDL_SHARED_READ(SR) 访问表结构并且读表数据 select * from t1; lock table t1 read;
会加如下锁:
(TABLE,MDL_TRANSACTION,MDL_SHARE_READ)
MDL_SHARED_WRITE(SW) 访问表结构并且写表数据 insert/update/delete/select .. for update
会加如下锁:
(TABLE,MDL_TRANSACTION,MDL_SHARE_WRITE)
MDL_SHARED_UPGRADABLE(SU) 是mysql5.6引入的新的metadata lock,
在alter table/create index/drop index会加该锁;可以说是为了online ddl才引入的。特点是允许DML,防止DDL;
(TABLE,MDL_TRANSACTION,MDL_SHARED_UPGRADABLE)
MDL_SHARED_NO_WRITE(SNW) 可升级锁,访问表结构并且读写表数据,并且禁止其它事务写。 alter table t1 modify c bigint;(非onlineddl)
(TABLE,MDL_TRANSACTION,MDL_SHARED_NO_WRITE)
MDL_SHARED_NO_READ_WRITE(SNRW) 可升级锁,访问表结构并且读写表数据,并且禁止其它事务读写。 lock table t1 write;加锁
(TABLE,MDL_TRANSACTION,MDL_SHARED_NO_READ_WRITE
MDL_EXCLUSIVE(X) 防止其他线程读写元数据 CREATE/DROP/RENAME TABLE,其他online DDL在rename阶段也持有X锁
(TABLE,MDL_TRANSACTION,MDL_EXCLUSIVE)

关于global对象
   主要作用是防止DDL和写操作的过程中,执行set golbal_read_only =on或flush tables with read lock;
 关于commit对象锁
  主要作用是执行flush tables with read lock后,防止已经开始在执行的写事务提交。
  insert/update/delete在提交时都会上(COMMIT,MDL_EXPLICIT,MDL_INTENTION_EXCLUSIVE)锁。

 

2.4 MDL 锁的兼容性矩阵

三、几种典型语句的加(释放)锁流程
1.select语句操作MDL锁流程
   1)Opening tables阶段,加共享锁
     a)   加MDL_INTENTION_EXCLUSIVE锁
     b)   加MDL_SHARED_READ锁
   2)事务提交阶段,释放MDL锁
     a)   释放MDL_INTENTION_EXCLUSIVE锁
     b)   释放MDL_SHARED_READ锁
2. DML语句操作MDL锁流程
  1)Opening tables阶段,加共享锁
     a)   加MDL_INTENTION_EXCLUSIVE锁
     b)   加MDL_SHARED_WRITE锁
  2)事务提交阶段,释放MDL锁
     a)   释放MDL_INTENTION_EXCLUSIVE锁
     b)   释放MDL_SHARED_WRITE锁
3. alter操作MDL锁流程
  1)Opening tables阶段,加共享锁
     a)   加MDL_INTENTION_EXCLUSIVE锁
     b)   加MDL_SHARED_UPGRADABLE锁,升级到MDL_SHARED_NO_WRITE锁
  2)操作数据,copy data,流程如下:
     a)   创建临时表tmp,重定义tmp为修改后的表结构
     b)   从原表读取数据插入到tmp表
  3)将MDL_SHARED_NO_WRITE读锁升级到MDL_EXCLUSIVE锁
     a)   删除原表,将tmp重命名为原表名
  4)事务提交阶段,释放MDL锁
     a)   释放MDL_INTENTION_EXCLUSIVE锁
     b)   释放MDL_EXCLUSIVE锁

四、典型问题分析
通常情况下我们关注MDL锁,大部分情况都是线上DB出现异常了。那么出现异常后,我们如何去判断是MDL锁导致的呢。监视MDL锁主要有两种方法,一种是通过show  processlist命令,判断是否有事务处于“Waiting for table metadata lock”状态,另外就是通过mysql的profile,分析特定语句在每个阶段的耗时时间。
抛出几个问题:
select 与alter是否会相互阻塞
dml与alter是否会相互阻塞
select与DML是否会相互阻塞
结合第三节几种语句的上锁流程,我们很容易得到这三个问题的答案。语句会在阻塞在具体某个环节,可以通过profile来验证我们的答案是否正确。
第一个问题,当执行select语句时,只要select语句在获取MDL_SHARED_READ锁之前,alter没有执行到rename阶段,那么select获取MDL_SHARED_READ锁成功,后续有alter执行到rename阶段,请求MDL_EXCLUSIVE锁时,就会被阻塞。rename阶段会持有MDL_EXCLUSIVE锁,但由于这个过程时间非常短(大头都在copy数据阶段),并且是alter的最后一个阶段,所以基本感觉不到alter会阻塞select语句。由于MDL锁在事务提交后才释放,若线上存在大查询,或者存在未提交的事务,则会出现ddl卡住的现象。这里要注意的是,ddl卡住后,若再有select查询或DML进来,都会被堵住,就会出现threadrunning飙高的情况。
第二个问题,alter在opening阶段会将锁升级到MDL_SHARED_NO_WRITE,rename阶段再将升级为MDL_EXCLUSIVE,由于MDL_SHARED_NO_WRITE与MDL_SHARED_WRITE互斥,所以先执行alter或先执行DML语句,都会导致语句阻塞在opening tables阶段。
第三个问题,显然,由于MDL_SHARED_WRITE与MDL_SHARED_READ兼容,所以它们不会因为MDL而导致等待的情况。

五 参考资料
 [1] 《MDL 锁介绍二 》他的三篇文章都值得一读,强烈推荐,本系列文章也是参考他的blog 写的。
 [2] 《DDL操作导致备库复制中断》 @印风的blog 为alisql/RDS 打了N多patch的牛人。

Metadata Lock原理6的更多相关文章

  1. Metadata Lock原理5

    [MySQL] 之一2015-09-05 15:46:51 分类: MySQL 一 简介 和MySQL打交道比较多的朋友,肯定遇到过 "Waiting for table metadata ...

  2. Metadata Lock原理4

     http://blog.chinaunix.net/uid-28212952-id-3400571.html    Alibaba  今天发生一个故障,MM复制结构(主备库),备库slave del ...

  3. Metadata Lock原理8

    http://www.kancloud.cn/taobaomysql/monthly/67141 MySQL· 5.7优化·Metadata Lock子系统的优化 背景 引入MDL锁的目的,最初是为了 ...

  4. Metadata Lock原理7

    http://blog.itpub.net/22664653/viewspace-1791744/ 一 简介 通过前面两篇文章的介绍,相信读到这里的各位对MDL 锁已经有了比较深入的了解了,本文将结合 ...

  5. Metadata Lock原理3

      http://blog.itpub.net/26515977/viewspace-1208250/   腾讯工程师 随着5.5.3引入MDL,更多的Query被“Waiting for table ...

  6. Metadata Lock原理2

    同事说开发机更改一个表结构,加字段,但是一直挂在那里,没反应.一开始以为表测试数据量很大,因为mysql增加表字段会重写表,后来看了下数据量很小,就另外查看过程.原因分析和处理如下:  一.环境  m ...

  7. Metadata Lock原理1

    https://www.percona.com/blog/2013/02/01/implications-of-metadata-locking-changes-in-mysql-5-5/ impli ...

  8. mysql metadata lock(三)

    前言 MDL锁主要用来保护Mysql内部对象的元数据,通过MDL机制保证DDL与DML以及SELECT查询操作的并发.MySQL Meta Lock(一)和MySQL Meta Lock(二)已经讲了 ...

  9. mysql metadata lock(二)

    上一篇<mysql metadata lock(一)>介绍了为什么引入MDL,MDL作用以及MDL锁导致阻塞的几种典型场景,文章的最后还留下了一个小小的疑问.本文将更详细的介绍MDL,主要 ...

随机推荐

  1. XTUOJ1250 Super Fast Fourier Transform 暴力

    分析:因为加起来不超过1e6,所以最多有1000+个不同的数 做法:离散化搞就好了 #include <cstdio> #include <iostream> #include ...

  2. delegate 为什么用 weak属性

    weak指针主要用于“父-子”关系,父亲拥有一个儿子的strong指针,因此是儿子的所有者:但是为了阻止所有权回环,儿子需要使用weak指针指向父亲:你的viewcontroller通过strong指 ...

  3. [GRYZ]寒假模拟赛

    写在前面 这是首次广饶一中的OIERS自编自导,自出自做(zuo)的模拟赛. 鉴于水平气压比较低,机(wei)智(suo)的WMY/XYD/HYXZC就上网FQ下海找了不少水(fei)题,经过他们优( ...

  4. bzoj 3365 [Usaco2004 Feb]Distance Statistics 路程统计(点分治,单调)

    [题意] 求树上长度不超过k的点对数目. [思路] 和 Tree 一样一样的. 就是最后统计的时候别忘把根加上. [代码] #include<set> #include<cmath& ...

  5. Matlab中imshow()函数的使用

    imread() 返回的图像类型是uint8类型, 这时用imshow显示图像的时候, imshow会认为输入矩阵的范围在0-255, 如果imshow的参数为double类型的,那么imshow认为 ...

  6. Node.js中的事件

    var util = require("util"); //导入util模块 var events = require("events"); //导入event ...

  7. JavaScript,通过分析Array.prototype.push重新认识Array

    在阅读ECMAScript的文档的时候,有注意到它说,数组的push方法其实不仅限于在数组中使用,专门留作通用方法.难道是说,在一些类数组的地方也可以使用?而哪些是和数组非常相像的呢,大家或许一下子就 ...

  8. Spring Object/XML mapping example

    In this tutorial, we will extend last Maven + Spring hello world example by adding JDBC support, to ...

  9. codeforce 621A(水题)

    A. Wet Shark and Odd and Even time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  10. [iOS微博项目 - 1.0] - 搭建基本框架

    A.搭建基本环境   github: https://github.com/hellovoidworld/HVWWeibo   项目结构:   1.使用代码构建UI,不使用storyboard     ...