详细分析mysql MDL元数据锁

前言:

当你在MySQL中执行一条SQL时,语句并没有在你预期的时间内执行完成,这时候我们通常会登陆到MySQL数据库上查看是不是出了什么问题,通常会使用的一个命令就是 show processlist,看看有哪些session,这些session在做什么事情。当你看到 waiting for table metadata lock 时,那就是遇到MDL元数据锁了。本篇文章将会介绍MDL锁的产生与排查过程。

1.什么是MDL锁

MDL全称为metadata lock,即元数据锁。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务(显式或隐式)的时候,不可以对元数据进行写入操作。因此从MySQL5.5版本开始引入了MDL锁,来保护表的元数据信息,用于解决或者保证DDL操作与DML操作之间的一致性。

对于引入MDL,其主要解决了2个问题,一个是事务隔离问题,比如在可重复隔离级别下,会话A在2次查询期间,会话B对表结构做了修改,两次查询结果就会不一致,无法满足可重复读的要求;另外一个是数据复制的问题,比如会话A执行了多条更新语句期间,另外一个会话B做了表结构变更并且先提交,就会导致slave在重做时,先重做alter,再重做update时就会出现复制错误的现象。

元数据锁是server层的锁,表级锁,每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥),申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。(这里有种特殊情况如果事务中包含DDL操作,mysql会在DDL操作语句执行前,隐式提交commit,以保证该DDL语句操作作为一个单独的事务存在,同时也保证元数据排他锁的释放)。

注意:支持事务的InnoDB引擎表和不支持事务的MyISAM引擎表,都会出现Metadata Lock Wait等待现象。一旦出现Metadata Lock Wait等待现象,后续所有对该表的访问都会阻塞在该等待上,导致连接堆积,业务受影响。

2.模拟与查找MDL锁

MDL锁通常发生在DDL操作挂起的时候,原因是有未提交的事务对该表进行DML操作。而MySQL的会话那么多,不知道哪个会话的操作没有及时提交影响了DDL。通常我们排查这类问题,往往需要从information_schema.innodb_trx表中查询当前在执行的事务,但当SQL已经执行过了,没有commit,这个时候这个表中是看不到SQL的。

在MySQL5.7中,performance_schema库中新增了metadata_locks表,专门记录MDL的相关信息。首先要开启MDL锁记录,执行如下SQL开启:

UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME = 'wait/lock/metadata/sql/mdl';

下面展示下模拟及查找MDL锁的过程:

# 会话1 事务中执行DML操作
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into student_tb (stu_id,stu_name) values (1009,'xin');
Query OK, 1 row affected (0.00 sec)

mysql> select * from student_tb;
+--------------+--------+----------+---------------------+---------------------+
| increment_id | stu_id | stu_name | create_time   | update_time   |
+--------------+--------+----------+---------------------+---------------------+
|   1 | 1001 | from1 | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   2 | 1002 | dfsfd | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   3 | 1003 | fdgfg | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   4 | 1004 | sdfsdf | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   5 | 1005 | dsfsdg | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   6 | 1006 | fgd  | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   7 | 1007 | fgds  | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   8 | 1008 | dgfsa | 2019-11-28 16:36:14 | 2019-11-28 16:36:14 |
|   9 | 1009 | xin  | 2019-11-28 17:05:29 | 2019-11-28 17:05:29 |
+--------------+--------+----------+---------------------+---------------------+

# 会话2 对该表加字段 执行DDL操作 发现DDL挂起
mysql> alter table student_tb add stu_age int after stu_name;

# 会话3 查询所有会话 发现发生MDL锁
mysql> show processlist;
+----+------+-----------+--------+---------+------+---------------------------------+-------------------------------------------------------+
| Id | User | Host  | db  | Command | Time | State       | Info             |
+----+------+-----------+--------+---------+------+---------------------------------+-------------------------------------------------------+
| 31 | root | localhost | testdb | Sleep | 125 |         | NULL             |
| 32 | root | localhost | testdb | Query | 7 | Waiting for table metadata lock | alter table student_tb add stu_age int after stu_name |
| 33 | root | localhost | testdb | Query | 0 | starting      | show processlist          |
+----+------+-----------+--------+---------+------+---------------------------------+-------------------------------------------------------+

# 会话3 查看metadata_locks表记录 发现student_tb表有MDL锁冲突
mysql> select * from performance_schema.metadata_locks;
+-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA  | OBJECT_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+
| TABLE  | testdb    | student_tb  |  94189250717664 | SHARED_WRITE  | TRANSACTION | GRANTED  |  |    56 |    34 |
| GLOBAL  | NULL    | NULL   |  139764477045472 | INTENTION_EXCLUSIVE | STATEMENT  | GRANTED  |  |    57 |    18 |
| SCHEMA  | testdb    | NULL   |  139764477697808 | INTENTION_EXCLUSIVE | TRANSACTION | GRANTED  |  |    57 |    18 |
| TABLE  | testdb    | student_tb  |  139764477697904 | SHARED_UPGRADABLE | TRANSACTION | GRANTED  |  |    57 |    18 |
| TABLE  | testdb    | student_tb  |  139764477697696 | EXCLUSIVE   | TRANSACTION | PENDING  |  |    57 |    18 |
| TABLE  | performance_schema | metadata_locks |  139764544135120 | SHARED_READ   | TRANSACTION | GRANTED  |  |    58 |    20 |
+-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+

# 会话3 联合其他系统表 查找出会话ID
mysql> select m.*,t.PROCESSLIST_ID from performance_schema.metadata_locks m left join performance_schema.threads t on m.owner_thread_id=t.thread_id;
+-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA  | OBJECT_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID | PROCESSLIST_ID |
+-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+----------------+
| TABLE  | testdb    | student_tb  |  94189250717664 | SHARED_WRITE  | TRANSACTION | GRANTED  |  |    56 |    34 |    31 |
| GLOBAL  | NULL    | NULL   |  139764477045472 | INTENTION_EXCLUSIVE | STATEMENT  | GRANTED  |  |    57 |    18 |    32 |
| SCHEMA  | testdb    | NULL   |  139764477697808 | INTENTION_EXCLUSIVE | TRANSACTION | GRANTED  |  |    57 |    18 |    32 |
| TABLE  | testdb    | student_tb  |  139764477697904 | SHARED_UPGRADABLE | TRANSACTION | GRANTED  |  |    57 |    18 |    32 |
| TABLE  | testdb    | student_tb  |  139764477697696 | EXCLUSIVE   | TRANSACTION | PENDING  |  |    57 |    18 |    32 |
| TABLE  | performance_schema | metadata_locks |  139764544135120 | SHARED_READ   | TRANSACTION | GRANTED  |  |    58 |    22 |    33 |
| TABLE  | performance_schema | threads  |  139764549217280 | SHARED_READ   | TRANSACTION | GRANTED  |  |    58 |    22 |    33 |
+-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+----------------+

# 结果解读:从上面结果明显可以看出会话31持有student_tb表的SHARED_WRITE锁,
# 需要等待其提交后或手动杀掉该会话方可解除MDL锁。

3.如何优化与避免MDL锁

MDL锁一旦发生会对业务造成极大影响,因为后续所有对该表的访问都会被阻塞,造成连接积压。我们日常要尽量避免MDL锁的发生,下面给出几点优化建议可供参考:

  • 开启metadata_locks表记录MDL锁。
  • 设置参数lock_wait_timeout为较小值,使被阻塞端主动停止。
  • 规范使用事务,及时提交事务,避免使用大事务。
  • 增强监控告警,及时发现MDL锁。
  • DDL操作及备份操作放在业务低峰期执行。
  • 少用工具开启事务进行查询,图形化工具要及时关闭。

总结:

本篇文章主要分三方面来详解MDL锁,首先介绍了MDL锁产生的原因及作用,然后我们模拟出MDL锁,并给出查找及解决方法,最后给出几点避免MDL锁的建议。其实,MDL锁在DB运维过程中经常遇到,它不是洪水猛兽,只是为了保护数据库对象,保证数据一致性。希望大家看完这篇文章后能对MDL锁有更清晰的认识。

以上就是详细分析mysql MDL元数据锁的详细内容,更多关于mysql MDL元数据锁的资料请关注我们其它相关文章!

(0)

相关推荐

  • MySQL如何查看元数据锁阻塞在哪里

    MySQL如何查看元数据锁阻塞在哪里 操作步骤: 1.session 1 执行: start transaction; select *from t1; 2.session 2 在第1步执行完后执行: drop table t1; 此时session 2的drop语句被阻塞.那么怎么分析查看元数据锁呢? 方法: 1)执行show processlist;,可以看到drop语句在等待元数据锁 mysql> show processlist; +----+-------------+--------

  • MYSQL METADATA LOCK(MDL LOCK)MDL锁问题分析

    一.前言 MYSQL中MDL锁一直是一个比较让人比较头疼的问题,我们谈起锁一般更加倾向于INNODB下层的gap lock.next key lock.row lock等,因为它很好理解,也很好观察,而对于MDL LOCK却了解得很少,因为它实在不好观察,只有出现问题查看show processlist勉强可以看到 简单的所谓的Waiting for table metadata lock之类的状态,其实MDL LOCK是MYSQL上层一个非常复杂的子系统,有自己的死锁检测机制 (无向图?)而大

  • 详细分析mysql MDL元数据锁

    前言: 当你在MySQL中执行一条SQL时,语句并没有在你预期的时间内执行完成,这时候我们通常会登陆到MySQL数据库上查看是不是出了什么问题,通常会使用的一个命令就是 show processlist,看看有哪些session,这些session在做什么事情.当你看到 waiting for table metadata lock 时,那就是遇到MDL元数据锁了.本篇文章将会介绍MDL锁的产生与排查过程. 1.什么是MDL锁 MDL全称为metadata lock,即元数据锁.MDL锁主要作用

  • 详细分析mysql视图的原理及使用方法

    前言: 在MySQL中,视图可能是我们最常用的数据库对象之一了.那么你知道视图和表的区别吗?你知道创建及使用视图要注意哪些点吗?可能很多人对视图只是一知半解,想详细了解视图的同学看过来哟,本篇文章会详细介绍视图的概念.创建及使用方法. 1.视图定义及简单介绍 视图是基于 SQL 语句的结果集的可视化的表,即视图是一个虚拟存在的表,可以包含表的全部或者部分记录,也可以由一个表或者多个表来创建.使用视图就可以不用看到数据表中的所有数据,而是只想得到所需的数据.当我们创建一个视图的时候,实际上是在数据

  • 详细分析MySQL主从复制

    前言: 在MySQL中,主从架构应该是最基础.最常用的一种架构了.后续的读写分离.多活高可用架构等大多都依赖于主从复制.主从复制也是我们学习MySQL过程中必不可少的一部分,关于主从复制的文章有很多,笔者也来凑凑热闹,写写这方面的内容吧,同时分享下自己的经验和方法. 1.主从复制简介及原理 主从复制(也称 AB 复制)是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中.对于多级复制,数据库服务器既可充当主机,也可充当从机.MySQL默认

  • 一文搞懂MySQL元数据锁(MDL)

    目录 一.什么是metadata lock 二.MDL和行锁有什么区别 三.MDL为什么会造成系统崩溃 四.MDL的生命周期有多长 五.如何快速找到阻塞源头 六.本文开始的案例最终如何解决 小结 某日,路上收到用户咨询,为了清除空间,想删除某200多G大表数据,且已经确认此表不再有业务访问,于是执行了一条命令‘delete from bigtable’,但好长时间也没删完,经过咨询后,获知drop table删除表速度快,而且能彻底释放空间,于是又在另外一个session中执行了‘drop ta

  • mysql中binlog_format模式与配置详细分析

    mysql复制主要有三种方式:基于SQL语句的复制(statement-based replication, SBR),基于行的复制(row-based replication, RBR),混合模式复制(mixed-based replication, MBR).对应的,binlog的格式也有三种:STATEMENT,ROW,MIXED. ① STATEMENT模式(SBR) 每一条会修改数据的sql语句会记录到binlog中.优点是并不需要记录每一条sql语句和每一行的数据变化,减少了binl

  • MySQL事务日志(redo log和undo log)的详细分析

    目录 前言 1.redo log 1.1 redo log和二进制日志的区别 1.2 redo log的基本概念 1.3 日志块(log block) 1.4 log group和redo log file 1.5 redo log的格式 1.6 日志刷盘的规则 1.7 数据页刷盘的规则及checkpoint 1.8 LSN超详细分析 1.9 innodb的恢复行为 1.10 和redo log有关的几个变量 2.undo log 2.1 基本概念 2.2 undo log的存储方式 2.3 和

  • MySQL InnoDB 事务锁源码分析

    目录 1. Lock 与 Latch 2. Repeatable Read 3. Insert加锁流程 3.1 lock mode 3.2 加锁流程 3.3 隐式锁 4. Select 加锁流程 本文前提: 代码MySQL 8.0.13 只整理Repeatable Read当前读.Read Committed简单很多,另外快照读是基于MVCC不用加锁,所以不在本文讨论范畴. 1. Lock 与 Latch InnoDB 中的lock是事务中对访问/修改的record加的锁,它一般是在事务提交或回

  • mysql详细分析讲解子查询的使用

    出现在其他语句中的 select 语句,称为子查询或内查询:外部的查询语句,称为主查询或 外查询 . -- 子查询 -- 查询的条件来自于另一查询的结果 SELECT * FROM t_user WHERE number=(SELECT number FROM t_user WHERE NAME='张三') 当然子查询也有类型,分为以下几种 : 标量子查询(结果集只有一行一列) 列子查询(结果集只有一列多行) 行子查询(结果集有一行多列)(较少) 表子查询(结果集一般为多行多列) 这里我们以新建

  • MySQL的主从复制原理详细分析

    目录 前言 一.主从复制概念 二.读写分离的概念 三.主库和从库 1. 主库 2. 从库 四.主从复制的流程 五.主从复制效果展示 前言 在实际生产环境中,如果对mysql数据库的读和写都在一台数据库服务器中操作,无论是在安全性.高可用性,还是高并发等各个方面都是不能满足实际需求的,一般要通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力. 一.主从复制概念 主从复制是MySQL提供的基本的技术,主从复制的流程:binlog二进制日志(除了查询其他的更改相关的操作都会记录在b

随机推荐