初步认知MySQL metadata lock(MDL)
随着5.5.3引入MDL,更多的Query被“Waiting for table metadata lock”给\'炕\'了
SHOW PROCESSLIST的输出也有之前的"Locked"变得粒度更加细的\'Waiting for table metadata lock\'
引入MDL,当需要访问、修改表结构时,都需要对元数据上锁(读/写)
MDL在Server层,保护表数据结构,而非数据本身。Server比之前版本繁忙多了
MDL意味着DDL,一旦DDL被阻塞,那么面向该表的所有Query都会被挂起,包括Select,不过5.6作了改进,5.5可通过参数控制
假如没有MDL
在5.1版本,MDL的生命随语句的结束而释放,并非在事务提交后结束,意味着事务不是真正的隔离
因为同一条Query在2次执行期间倘若被插入了DDL,那么得到的结果将会不同,下面是个例子
- 会话1:
- mysql> select version();
- +------------+
- | version() |
- +------------+
- | 5.1.72-log |
- +------------+
- 1 row in set (0.00 sec)
- mysql> select @@tx_isolation;
- +-----------------+
- | @@tx_isolation |
- +-----------------+
- | REPEATABLE-READ |
- +-----------------+
- 1 row in set (0.00 sec)
- mysql> begin;
- Query OK, 0 rows affected (0.00 sec)
- mysql> select * from t where id=1;
- +----+--------+
- | id | name |
- +----+--------+
- | 1 | python |
- +----+--------+
- 1 row in set (0.04 sec)
- 会话2:
- mysql> alter table t add column comment varchar(200) default \'I use Python\';
- Query OK, 3 rows affected (0.02 sec)
- Records: 3 Duplicates: 0 Warnings: 0
- 会话1:
- mysql> select * from t where id=1;
- Empty set (0.00 sec)
- mysql> rollback;
- Query OK, 0 rows affected (0.00 sec)
- mysql> begin;
- Query OK, 0 rows affected (0.00 sec)
- mysql> select * from t where id=1;
- +----+--------+--------------+
- | id | name | comment |
- +----+--------+--------------+
- | 1 | python | I use Python |
- +----+--------+--------------+
- 1 row in set (0.00 sec)
与上面的不同,在5.5 MDL拉长了生命长度,与事务同生共死,只要事务还在,MDL就在,由于事务持有MDL锁,任何DDL在事务期间都休息染指,下面是个例子
- 会话1:
- mysql> select version();
- +------------+
- | version() |
- +------------+
- | 5.5.16-log |
- +------------+
- 1 row in set (0.01 sec)
- mysql> begin;
- Query OK, 0 rows affected (0.00 sec)
- mysql> select * from t order by id;
- +----+------+
- | id | name |
- +----+------+
- | 1 | a |
- | 2 | e |
- | 3 | c |
- +----+------+
- 3 rows in set (0.00 sec)
- 会话2:
- mysql> alter table t add column cc char(10) default \'c lang\'; <<===Hangs
- 会话3:
- mysql> show processlist;
- +----+------+-----------+------+---------+------+---------------------------------+-------------------------------------------------------+
- | Id | User | Host | db | Command | Time | State | Info |
- +----+------+-----------+------+---------+------+---------------------------------+-------------------------------------------------------+
- | 2 | root | localhost | db1 | Sleep | 191 | | NULL |
- | 3 | root | localhost | db1 | Query | 125 | Waiting for table metadata lock | alter table t add column cc char(10) default \'c lang\' |
- | 4 | root | localhost | NULL | Query | 0 | NULL | show processlist |
- +----+------+-----------+------+---------+------+---------------------------------+-------------------------------------------------------+
回滚了会话1的事务后,我们看下alter主要被谁炕了
- mysql> show profiles;
- +----------+---------------+-------------------------------------------------------+
- | Query_ID | Duration | Query |
- +----------+---------------+-------------------------------------------------------+
- | 1 | 1263.64100500 | alter table t add column dd char(10) default \' Elang\' |
- +----------+---------------+-------------------------------------------------------+
- 1 row in set (0.00 sec)
- mysql> show profile for query 1;
- +------------------------------+------------+
- | Status | Duration |
- +------------------------------+------------+
- | starting | 0.000124 |
- | checking permissions | 0.000015 |
- | checking permissions | 0.000010 |
- | init | 0.000023 |
- | Opening tables | 0.000063 |
- | System lock | 0.000068 |
- | setup | 0.000082 |
- | creating table | 0.034159 |
- | After create | 0.000185 |
- | copy to tmp table | 0.000309 |
- | rename result table | 999.999999 |
- | end | 0.004457 |
- | Waiting for query cache lock | 0.000024 |
- | end | 0.000029 |
- | query end | 0.000009 |
- | closing tables | 0.000030 |
- | freeing items | 0.000518 |
- | cleaning up | 0.000015 |
- +------------------------------+------------+
- 18 rows in set (0.00 sec)
显然,在"rename result table"处发生了等待,在我们alter一张大表的时候,真正触礁的地方也就这里,这也呼应下面的案例1
案例
案例 1:
5.5下给大表加主键时会锁住读的问题
加锁策略:
1)上MDL读锁
2)操作数据,最耗时,需copy data,简易流程如下:
a) 创建临时表A,重定义A为修改后的表结构
b) 从原表读取数据插入到A表
3)将MDL读锁升级为写锁
c) 删除原表,将A重命名为原表名
4)释放MDL写锁
5.5必须在打开了old_alter_table后才会采取上述策略,但事实上,无论其是否打开
对主键操作都必须copy data,基于此5.6已经改进,从而把MDL写锁仅圈在重命名的操作
这样阻塞时间非常之短,几乎可以认为不阻塞读,在5.5时做alter建议将其打开,减小持锁时间
案例 2:
mysqldump备份不一致导致备库延迟问题
由于5.1中没有引入MDL,所有在mysqldump备份过程中,并发DDL都会对其产生影响,导致备份集不一致
最终表现是使用此备份集恢复的备库在relay主库binlog会出现slave error,造成在备库上的读与主库数据不一致
因为5.5有了MDL,所以–single-transaction时,事务内操作过的表都会持有MDL,因此不会被DDL破坏
例如,mysqldump已经备份了a,b,c表,因为它们在事务内,事务还没提交,它们的MDL不会释放
因此另外的线程如果做a,b,c中任意一张表的DDL操作,都会出现Waiting for table metadata lock,而还没备份到的表不会持有MDL,因此还可以做DDL
监控
lock_wait_timeout
- mysql> show variables like \'lock_wait_timeout\';
- +-------------------+----------+
- | Variable_name | Value |
- +-------------------+----------+
- | lock_wait_timeout | 31536000 |
- +-------------------+----------+
- 1 row in set (0.00 sec)
官方文档解释:
- This variable specifies the timeout in seconds for attempts to acquire metadata locks.
- The permissible values range from 1 to 31536000 (1 year). The default is 31536000
5.5默认是1年!太长了,个人认为不是很合理,这个需要我们DBA自己调整,50秒会比较好
另外,这个既然针对MDL的超时设置,那为何不命名为"metadata_lock_wait_timeout"呢?
show open tables:当前打开的表,与flush tables结合,能判断表的活性
show status like \'Open%tables\';是上面的简化输出
诊断
对于MyISAM表:
当发现Query由于“Waiting for table metadata lock”而挂起等待MyISAM表,这是因为该表已经被包含在一个未提交的事务,无论其是否有意
而且常见的锁追踪技巧此时也没有作用,比如InnoDB Lock Monitor, InnoDB Status, mysqladmin debug output, INFORMATION_SCHEMA等
事实上,在select一张表之前先SET AUTOCOMMIT=0,那么之后,直到该事务提交或结束后其它DDL才能够得到该表的控制权
测试:
- Connection #1:
- create table t1 (id int) engine=myisam;
- set @@autocommit=0;
- select * from t1;
- Connection #2:
- alter table t1 rename to t2; <-- Hangs
对于InnoDB表:
倘若在InnoDB表遇见此问题,我们能够用SHOW ENGINE INNODB STATUS,优先查看transactions部分
测试:
- create table t3 (id int) engine=innodb;
- create table t4 (id int) engine=innodb;
- delimiter |
- CREATE TRIGGER t3_trigger AFTER INSERT ON t3
- FOR EACH ROW BEGIN
- INSERT INTO t4 SET id = NEW.id;
- END;
- |
- delimiter ;
- Connection #1:
- begin;
- insert into t3 values (1);
- Connection #2:
- drop trigger if exists t3_trigger; <-- Hangs
- mysql> SHOW ENGINE INNODB STATUS\G;
- ....
- ....
- ....
- ------------
- TRANSACTIONS
- ------------
- Trx id counter BF03
- Purge done for trx\'s n:o < BD03 undo n:o < 0
- History list length 82
- LIST OF TRANSACTIONS FOR EACH SESSION:
- ---TRANSACTION 0, not started
- MySQL thread id 4, OS thread handle 0xa7d3fb90, query id 40 localhost root
- show engine innodb status
- ---TRANSACTION BF02, ACTIVE 38 sec
- 2 lock struct(s), heap size 320, 0 row lock(s), undo log entries 2
- MySQL thread id 2, OS thread handle 0xa7da1b90, query id 37 localhost root
- ...
- ...
- ...
官方文档对 TRANSACTIONS解释:
- TRANSACTIONS
- If this section reports lock waits, your applications might have lock contention.
- The output can also help to trace the reasons for transaction deadlocks.
除此之外,我们还可以利用information_schema,以下是几个有用SQL:
① 锁等待
- SELECT * FROM INNODB_LOCK_WAITS
② 被阻塞的事务
- SELECT *
- FROM INNODB_LOCKS
- WHERE LOCK_TRX_ID IN (SELECT BLOCKING_TRX_ID FROM INNODB_LOCK_WAITS)
或者
- SELECT INNODB_LOCKS.*
- FROM INNODB_LOCKS
- JOIN INNODB_LOCK_WAITS
- ON (INNODB_LOCKS.LOCK_TRX_ID = INNODB_LOCK_WAITS.BLOCKING_TRX_ID)
③ 指定表上的锁
- SELECT * FROM INNODB_LOCKS
- WHERE LOCK_TABLE = db_name.table_name
④ 事务与锁
- SELECT TRX_ID, TRX_REQUESTED_LOCK_ID, TRX_MYSQL_THREAD_ID, TRX_QUERY
- FROM INNODB_TRX
- WHERE TRX_STATE = \'LOCK WAIT\'
当然,最好的办法还是综合运用前面2种
与table cache的关系
先明白table cache所解决的问题域:fd(文件描述符)打开/关闭太过频繁导致资源消耗
那么它是如何解决的?tc通过cache所有打开的fd,当有新的连接请求时不需重新打开,结束后也不用关闭
DDL操作终究会被阻塞,即使table cache含有其所需的fd。MySQL认为,tc旧条目必须失效
访问该表的DDL操作必须重新打开fd,下面是个测试
- 会话1:
- mysql> show status like \'Open%tables\';
- +---------------+-------+
- | Variable_name | Value |
- +---------------+-------+
- | Open_tables | 26 | <==当前打开的表数量
- | Opened_tables | 2 | <==已经打开的表数量
- +---------------+-------+
- 2 rows in set (0.00 sec)
- 会话2:
- mysql> alter table t add column Oxx char(20) default \'ORACLE\';
- Query OK, 3 rows affected (0.05 sec)
- Records: 3 Duplicates: 0 Warnings: 0
- 会话1:
- mysql> select * from t order by id;
- +----+------+--------+--------+---------+---------+-------+--------+--------+--------+--------+
- | id | name | cc | dd | EE | ff | OO | OE | OF | OX | Oxx |
- +----+------+--------+--------+---------+---------+-------+--------+--------+--------+--------+
- | 1 | a | c lang | Elang | Golang | Golang | MySQL | ORACLE | ORACLE | ORACLE | ORACLE |
- | 2 | e | c lang | Elang | Golang | Golang | MySQL | ORACLE | ORACLE | ORACLE | ORACLE |
- | 3 | c | c lang | Elang | Golang | Golang | MySQL | ORACLE | ORACLE | ORACLE | ORACLE |
- +----+------+--------+--------+---------+---------+-------+--------+--------+--------+--------+
- 3 rows in set (0.00 sec)
- mysql> show status like \'Open%tables\';
- +---------------+-------+
- | Variable_name | Value |
- +---------------+-------+
- | Open_tables | 27 |
- | Opened_tables | 3 |
- +---------------+-------+
- 2 rows in set (0.00 sec)
- 会话2:
- mysql> alter table t add column Oxf char(20) default \'ORACLE\';
- Query OK, 3 rows affected (0.06 sec)
- Records: 3 Duplicates: 0 Warnings: 0
- 会话1:
- mysql> show status like \'Open%tables\';
- +---------------+-------+
- | Variable_name | Value |
- +---------------+-------+
- | Open_tables | 26 |
- | Opened_tables | 3 |
- +---------------+-------+
- 2 rows in set (0.00 sec)
结论:
当需要对"热表"做DDL,需要特别谨慎,否则,容易造成MDL等待,导致连接耗尽或者拖垮Server
参考资料:
http://dinglin.iteye.com/blog/1884696
http://www.xaprb.com/blog/2012/08/28/debugging-metadata-locking-in-mysql-5-5/
http://blog.chinaunix.net/uid-28212952-id-3400571.html
http://www.chriscalender.com/?p=1189
http://www.mysqlperformanceblog.com/2013/02/01/implications-of-metadata-locking-changes-in-mysql-5-5/
By 迦叶
2013-12-17
Good Luck
初步认知MySQL metadata lock(MDL)的更多相关文章
- mysql metadata lock(二)
上一篇<mysql metadata lock(一)>介绍了为什么引入MDL,MDL作用以及MDL锁导致阻塞的几种典型场景,文章的最后还留下了一个小小的疑问.本文将更详细的介绍MDL,主要 ...
- mysql metadata lock(一)
想必玩过mysql的人对Waiting for table metadata lock肯定不会陌生,一般都是进行alter操作时被堵住了,导致了我们在show processlist 时,看到线程的状 ...
- mysql metadata lock(三)
前言 MDL锁主要用来保护Mysql内部对象的元数据,通过MDL机制保证DDL与DML以及SELECT查询操作的并发.MySQL Meta Lock(一)和MySQL Meta Lock(二)已经讲了 ...
- mysql metadata lock锁
很多情况下,很多问题从理论上或者管理上而言都是可以避免或者说很好解决的,但是一旦涉及到现实由于管理或者协调或者规范执行的不够到位,就会出现各种各样本不该出现的问题,这些问题的通常在生产环境并不会出现, ...
- mysql metadata lock
想必玩过mysql的人对Waiting for table metadata lock肯定不会陌生,一般都是进行alter操作时被堵住了,导致了我们在show processlist 时,看到线程的状 ...
- MySQL Metadata Lock详解
Metadata Lock 的作用: 要直接说出Metadata Lock 的作用.以我目前的文字功底是不行的.好在我可以通过一个例子来说明. 假设session 1 在正在执行如下的SQL语句 se ...
- Metadata Lock原理5
[MySQL] 之一2015-09-05 15:46:51 分类: MySQL 一 简介 和MySQL打交道比较多的朋友,肯定遇到过 "Waiting for table metadata ...
- Mysql事物与Metadata lock 问题
环境说明: MySQL 5.6.16 OS:Linux RedHat 6.2 64bit 1.问题描述 目前新上一个使用MySQL数据库项目,在数据库中,每隔5分钟做truncate某 ...
- MetaData Lock 杨奇龙 ---MYSQL博客专家
http://blog.itpub.net/22664653/viewspace-1791608/ http://blog.csdn.net/dba_waterbin/article/details/ ...
随机推荐
- 《Python CookBook2》 第一章 文本 - 每次处理一个字符 && 字符和字符值之间的转换
文本 - 总结: 什么是文本Python 中的string 类型是不可变类型.文本,一个字符的矩阵,每一个单独的文本快可以被缩进和组织起来. 基本的文本操作①解析数据并将数据放入程序内部的结构中:②将 ...
- 为Fitnesse-20140630定制RestFixture代码
摘要:Fitnesse插件RestFixture在最新版Fitnesse输出测试结果为html文本,而非html.本博文记录RestFixture定制代码的过程. 准备开发环境 假定你已经正确安装JD ...
- 【九度OJ】题目1201-二叉排序树
题目 建树过程是递归,"递归的思路不是很复杂",经过题目1078的训练,直接开始编码.提交及修改的过程告诉自己,这是一个错觉,对递归的理解还应该再进一步. 自己的实现 #inclu ...
- well-posed problem and ill-posed problem
well-posed problem must have the property that A solution exists The solution is unique The solution ...
- JAVA中的异常(异常处理流程、异常处理的缺陷)
异常处理流程 1)首先由try{...}catch(Exception e){ System.out.println(e); e.printStackTrace(); }finally{...}结构 ...
- 最简单例子图解JVM内存分配和回收
一.简介 JVM采用分代垃圾回收.在JVM的内存空间中把堆空间分为年老代和年轻代.将大量(据说是90%以上)创建了没多久就会消亡的对象存储在年轻代,而年老代中存放生命周期长久的实例对象.年轻代中又被分 ...
- pku3670 Eating Together
http://poj.org/problem?id=3670 DP,最长不降子序列,O(n*logn)解法 #include <stdio.h> #define N 30030 int n ...
- ubuntu14.04.03 vsftpd
apt-get install vsftpd /etc/vsftpd.conf配置Example listen=YES anonymous_enable=NO local_enable=YES wri ...
- HDU4456-Crowd(坐标旋转+二位树状数组+离散化)
转自:http://blog.csdn.net/sdj222555/article/details/10828607 大意就是给出一个矩阵 初始每个位置上的值都为0 然后有两种操作 一种是更改某个位置 ...
- CoffeeScript学习(1)——Quick Start
什么是CoffeeScript CoffeeScript 是一门编译到 JavaScript 的小巧语言. 在 Java 般笨拙的外表下, JavaScript 其实有着一颗华丽的心脏. Coffee ...