mysql metadata lock(三)
前言
MDL锁主要用来保护Mysql内部对象的元数据,通过MDL机制保证DDL与DML以及SELECT查询操作的并发。MySQL Meta Lock(一)和MySQL Meta Lock(二)已经讲了一些关于MDL知识,本文将会对MDL进行一个补充,并解释查询堵塞和mysqldump获取一致性备份的原理。
一、MDL锁类型
1.按类型划分
2.按对象/范围维度划分
|
属性 |
含义 |
范围/对象 |
|
GLOBAL |
全局锁 |
范围 |
|
COMMIT |
提交保护锁 |
范围 |
|
SCHEMA |
库锁 |
对象 |
|
TABLE |
表锁 |
对象 |
|
FUNCTION |
函数锁 |
对象 |
|
PROCEDURE |
存储过程锁 |
对象 |
|
TRIGGER |
触发器锁 |
对象 |
|
EVENT |
事件锁 |
对象 |
MDL锁主要包括DB对象和范围两个维度,对象的MDL我们很好理解,为了保护对象的元数据。那么范围级别的锁呢?锁本质是为了保护共享资源,所以范围和对象都可以理解为一种资源。MYSQL约定某些操作必需要上COMMIT范围锁或GLOBAL范围锁,通过这种同步机制,保证各个线程有序运转。后面会结合案例详细讨论COMMIT和GLOBAL锁的应用场景。
3.按请求/释放锁持续时间划分
|
属性 |
含义 |
|
MDL_ STATEMENT |
语句级别 |
|
MDL_TRANSACTION |
事务级别 |
|
MDL_EXPLICIT |
需要显示释放 |
MDL另外一个属性是持有时间。如果是STATEMENT,则表示单个语句执行完毕后,MDL释放;TRANSACTION级别表示,事务结束后,MDL锁释放;前两者都是隐式锁,即请求锁和释放锁都是系统内部行为,用户无需发指令,而MDL_EXPLICIT表示MDL锁是显示请求和释放的。比如:flush table with read lock这个指令会显示上GLOBAL:MDL_EXPLICIT:SHARED和COMMIT:MDL_EXPLICIT:SHARED锁;需要通过UNLOCK TABLES指令显示释放。
4.范围锁的兼容性矩阵

5.举个栗子
begin:
update t3 set c1=1 where id=1;
commit;
|
流程 |
执行语句 |
执行内容 |
字典锁 |
|
1 |
begin |
释放MDL release_transactional_locks |
|
|
2 |
update t3 set c1=1 where id=1; |
请求 STATEMENT MDL |
GLOBAL:STATMENT MDL_INTENTION_EXCLUSIVE |
|
3 |
请求 TRANSACTION MDL |
TABLE:TRANSACTION MDL_SHARED_WRITE |
|
|
6 |
执行更新 |
||
|
7 |
释放 STATEMENT MDL |
GLOBAL:STATMENT |
|
|
8 |
commit; |
请求 COMMIT MDL |
COMMIT: MDL_EXPLICIT MDL_INTENTION_EXCLUSIVE |
|
9 |
执行提交 |
||
|
11 |
释放 COMMIT MDL 释放 TRANSACTION MDL |
COMMIT: MDL_EXPLICIT MDL_INTENTION_EXCLUSIVE |
|
|
12 |
release_transactional_locks TABLE:TRANSACTION |
二、请求锁/释放锁原理
锁兼容矩阵在metadata lock(二)已经有详细的介绍,仔细看代码发现MDL的锁兼容矩阵实际上包含两部分:活跃锁兼容矩阵,等待锁兼容矩阵。当请求锁时,需要保证两个矩阵对应的值都兼容,才能请求锁成功。为什么要设计等待锁兼容矩阵?我理解这里主要是优先保证DDL操作。因为如果DDL操作在等待一个查询操作时,其他查询还源源不断地进入,可能会导致DDL永远也拿不到锁,而实际情况下,DDL操作的重要性往往比查询或DML重要地多。
1. 请求锁兼容性检查:
1) 检查请求锁是否与已经存在的活跃锁冲突,若冲突,则等待;
2) 检查请求锁是否与已经存在的等待锁冲突,若冲突,则等待。
3) 请求锁成功。
2. 释放锁时机:
1) 语句执行结束后,释放STAMENT类型的锁
2) 事务提交时,先后请求COMMIT类型和释放COMMIT类型的锁
3) 事务提交后,释放TRANSACTION类型的锁
三、MDL应用场景分析
MDL是Mysql层面很重要的锁,很多常见问题的源头以及功能实现都依赖于MDL,以下我会举几个常见的问题和功能进行分析。
1. 为什么查询也会被阻塞?
我们在实际运维过程中,一个常见的场景是,接到手机threadrunning飙高告警,登上主机,show processlist看到一大片线程处于“Waiting for table metadata lock”状态,当然其中也包含查询。下面我通过一个简单的例子重新这个场景。
|
时间点 |
会话A |
会话B |
会话C |
|
|
1 |
begin update t3 set c1=1 where id=1; |
|||
|
2 |
返回 |
|||
|
3 |
alter table t3 add column c3 int; |
|||
|
4 |
等待 |
|||
|
5 |
select * from t3 |
|||
|
6 |
等待 |
|||
|
7 |
show processlist 返回结果 |
|||
|
8 |
init |
show processlist |
||
|
Waiting for table metadata lock |
alter table t3 add column c3 int |
|||
|
Waiting for table metadata lock |
select * from t3 |
|||
从表2可以看到A会话未提交的事务堵住了回话B的DDL语句,而DDL语句进而又堵住了会话C,从第8步来看,会话B和会话C都处于“Waiting for table metadata lock”状态。从表1我们可以看到,会话A的DML操作会请求TABLE- TRANSACTION- MDL_SHARED_WRITE锁,由于没有执行COMMIT,会一直持有;会话B的DDL操作会请求TABLE-TRANSACTION-EXCLUSIVE锁,由于两把锁互斥,等待;会话C的查询操作会请求TABLE- TRANSACTION- MDL_SHARED_READ锁,虽然MDL_SHARED_READ与活跃锁MDL_SHARED_WRITE不冲突,但是与回话B的等待锁EXCLUSIVE冲突,因此也会等待。遇到这种情况,首先要看看是否存在堵住的DDL,如果存在DDL,然后查询是否有大查询或者未提交的事务,这两种情况都会导致DDL堵住,进而影响普通的查询和DML操作。
2. Mysqldump与全局锁
在实际生产环境中,为了容灾和负载均衡,数据库服务一般由一主一备一对实例组成,主库对外提供读写服务,备库提供只读服务,或纯粹为了容灾使用。在这种体系下,通过mysqldump搭建新的实例时,需要获得一个一致性备份集,并且获得对应的位点(拉取主库binlog的依据),通过全量+增量的方式复制一个数据库实例。Mysqldump中为了保证一致性备份和获取对应的位点,需要设置两个关键的参数--master-data=2 和--single-transaction。我们可以通过mysqld的trace功能,跟踪Mysqldump执行的语句。假设我们要备份chuck库,命令如下:
./bin/mysqldump -uchuck -pchuck -P4006 –h127.0.0. --databases chuck mysql --master-data= --single-transaction --default-character-set=utf8 > chuck_dump.sql >chuck_dump.log
开启mysqld的trace功能
--debug=d,query,general:O,/kkk/mysqld.trace
通过mysqld.trace,我大概整理了关键的语句,分析和结果如下图所示。可以看到,mysqldump获取增量位点主要是通过FLUSH TABLES WITH READ LOCK语句的两把字典锁来实现(GLOBAL LOCK和COMMIT LOCK)。整个过程持续时间不长(如果语句没有被阻塞),获取位点后,立即将MDL锁释放。第2到第6步即为持有MDL锁的时间,这段时间内无法开启新事务,已有的事务也无法提交,保证位点的正确性。设置隔离级别为RR,则是获取一致性备份的关键,一致性备份的获取源于MVCC,关于MVCC的实现,后续可以单独写一篇文章。第8到第9步为一个表的备份过程, select语句会获取MDL锁(TABLE:TRANSACTION: MDL_SHARED_READ),执行完毕后,通过rollback语句释放MDL锁。因此除了备份的当前表不能做DDL操作;当前表的DML,以及其它表的DDL和DML都不受影响,所以Mysqldump备份过程中,基本不会阻塞线上的其他语句执行。
|
步骤 |
关键语句 |
含义 |
作用 |
|
1 |
FLUSH /*!40101 LOCAL */ TABLES |
关闭打开表 |
清空查询缓存 |
|
2 |
FLUSH TABLES WITH READ LOCK |
上GLOBAL字典锁: GLOBAL: MDL_SHARED COMMIT: MDL_SHARED |
阻塞新事务,以及活跃事务提交。 为获取一致性位点做准备 |
|
3 |
SET SESSION TRANSACTION ISOLATION LEVEL |
设置事务的隔离级别为RR |
保证快照读 |
|
4 |
START TRANSACTION /*!40100 WITH CONSISTENT |
开启事务 |
|
|
5 |
SHOW MASTER STATUS |
获取binlog 位点 |
用来获取主库的增量的位点 |
|
6 |
UNLOCK TABLES |
释放 GLOBAL字典锁 |
允许其它事务更新 |
|
7 |
SAVEPOINT sp |
设置保存点 |
后续可以逐个表 释放MDL |
|
8 |
SELECT /*!40001 SQL_NO_CACHE */ * FROM |
获取表t1的数据 TABLE:TRANSACTION MDL_SHARED_READ |
一致性读 |
|
9 |
ROLLBACK TO SAVEPOINT sp |
释放: TABLE:TRANSACTION MDL_SHARED_READ |
|
|
10 |
SELECT /*!40001 SQL_NO_CACHE */ * FROM `t2` |
获取表t2的数据 TABLE:TRANSACTION MDL_SHARED_READ |
一致性读 |
|
11 |
ROLLBACK TO SAVEPOINT sp |
释放: TABLE:TRANSACTION MDL_SHARED_READ |
|
|
12 |
…… |
||
|
13 |
备份完成 |
参考文章
http://www.percona.com/blog/2010/04/24/how-fast-is-flush-tables-with-read-lock/
http://blogread.cn/it/article/2338?f=hot1
http://imysql.cn/2008_10_24_deep_into_mysqldump_options
mysql metadata lock(三)的更多相关文章
- 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锁
很多情况下,很多问题从理论上或者管理上而言都是可以避免或者说很好解决的,但是一旦涉及到现实由于管理或者协调或者规范执行的不够到位,就会出现各种各样本不该出现的问题,这些问题的通常在生产环境并不会出现, ...
- 初步认知MySQL metadata lock(MDL)
http://blog.itpub.net/26515977/viewspace-1208250/ 概述 随着5.5.3引入MDL,更多的Query被“Waiting for table metada ...
- 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出现Waiting for table metadata lock的原因以及解决方法
转自:http://ctripmysqldba.iteye.com/blog/1938150 (有修改) MySQL在进行alter table等DDL操作时,有时会出现Waiting for tab ...
- 【转】【MySql】Waiting for table metadata lock原因分析
MySQL在进行alter table等DDL操作时,有时会出现Waiting for table metadata lock的等待场景.而且,一旦alter table TableA的操作停滞在Wa ...
随机推荐
- JS获取子窗口中返回的数据
在开发的时候,遇到了这样一个问题,客户填写自己的收货地址,可以新建,但同时也可以选择之前填写的,由于我们的客户本身就是商户,地址繁多,把它之前的地址简单用个下拉框罗列出来显然不合适,并且客户要求能够对 ...
- pageEncoding的默认设置
windows-->preference-->myeclipse-->files and editors-->jsp 右侧 Encoding 选择 ISO 10646/Uni ...
- 什么是CGI
什么是CGI 1. 定义: CGI(Common Gateway Interface)是HTTP服务器与你的或其它机器 上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上. 2. 功能: 绝大 ...
- 关于【error C3646: 未知重写说明符】的若干种可能性
如果在程序中出现了error C3646,那么这个错误可能是由多种问题所导致的,这篇文章将对多种错误及对应解决方法进行分析. 在MSDN的官方网站中,Complier Error C3646的定义为u ...
- hdu-1856-More is better
More is better Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 327680/102400 K (Java/Others) ...
- opencart二次开发小记
在controller中如果要调用model中数据或说方法可以这样写 $this->load->model('catalog/information');//model中的informat ...
- Play!中使用HTTP异步编程
本章译者:@Sam Liu (译者未留下自己的主页,请Sam Liu见此文,加入群168013302联系‘大黄蜂@翻译play’) 这一章主要讲解如何运用异步模式实现典型的长连接(long-polli ...
- 一款开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control
甘特图在项目管理中非常重要,甘特图的思想比较简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间.它直观地表明任务计划在什么时候进行,及实际进展与计划要求的对比.管理 ...
- (转)高性能JavaScript:加载和运行(动态加载JS代码)
浏览器是如何加载JS的 当浏览器遇到一个<script>标签时,浏览器首先根据标签src属性下载JavaScript代码,然后运行JavaScript代码,继而继续解析和翻译页面.如果需要 ...
- webstorm常用的快捷键总结
1. ctrl + shift + n: 打开工程中的文件,目的是打开当前工程下任意目录的文件. 2. ctrl + j: 输出模板 3. ctrl + b: 跳到变量申明处 4. ctrl + al ...