mysql锁系列之MDL元数据锁之一

2023-05-16

基础材料:

centos7.5 mysql 5.7.24


当mysql运行一条SQL语句时,在你预期的时间内,没有完成时,我们都会登陆到mysql数据库上想查看是不是出了什么问题,通常会使用的一个命令就是 show processlist,看看有哪些session,这些session在做什么事情。就从这个命令开始,显示如下:

 图中看到了显示了几处信息:

 id:为session_id,也就是processlist_id

 user:该session使用什么用户登陆的mysql数据库

 host:客户端登陆的ip地址(这里我都是本地登陆的)

 db:连接了哪个数据库(这里我只是连接上了数据库,并没有其他操作,所以都是NULL)

 command:当前session执行命令的类型

 Time:处于当前命令类型持续的时间

 State:当前命令类型的状态

 Info:具体命令信息


了解上面内容的含义后,初始化一下测试环境,模拟MDL锁等待,各个session按顺序执行命令如下:

id 41id 42id 43id 44id 45
 begin;begin;alter table testok add z varchar(10) not Null;select * from testok;
 select * from testok limit 1;select * from testok limit 1;  

 

 

 

 

说明:测试环境有一个test库,里面有一张表testok(innodb),里面有几行数据。在id 41没有执行任何命令,该session用于查看结果。id 42 开启一个事务,接着执行了一条查询语句,紧接着id 43 开启一个事务,也执行了一条查询语句。id 44为该表添加一个字段,id 45查询testok表。

这时在id 41 执行show processlist,结果如下:

 

可以看到与之前的一些变化,其中id 44 45的state变成了 Waiting for table metadata lock,即等待元数据锁,后面的Info即为上面执行命令。


这里简单解释一下产生元数据锁的原因,元数据锁是server层的锁,表级锁,主要用于隔离DML和DDL操作之间的干扰。每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥),申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。(这里有种特殊情况如果事务中包含DDL操作,mysql会在DDL操作语句执行后,隐式提交commit,以保证该DDL语句操作作为一个单独的事务存在,同时也保证元数据排他锁的释放,例如id 44的语句改为<begin;alter table testok add z varchar(10) not Null;select * from testok;>,此时一旦alter语句执行完成会马上提交事务(autocommit=1),后面的select就在本次事务之外,其执行完成后不会持有读锁)

下表为总结的表级元数据锁信息:

1、SHARED_UPGRADABLE本身为读锁但有些特殊,所以列表里把它的优先级设置为0.

      一、并不受队列中的写锁等待而阻塞,只和当前持锁的session比对,当前持锁session为排他锁X,则等待,反之获得锁

      二、为了保证一张表同时只有一个DDL操作进行,SHARED_UPGRADABLE之间是互斥的,即一个时刻只有一个SHARED_UPGRADABLE是GRANTED状态,其余是被阻塞。

2、EXCLUSIVE、SHARED_NO_READ_WRITE级别相同,在队列中排队,先进先出。

3、SHARED_WRITE与SHARED_READ兼容,但SHARED_WRITE优先级高于SHARED_READ_ONLY且不兼容

4、SHARED_READ与SHARED_WRITE和SHARED_READ_ONLY分别兼容。即如果前面的持锁类型为SHARED_WRITE,则可以获得锁。如果前面持锁类型为SHARED_READ_ONLY,也可以获得锁。

5、SHARED_READ_ONLY优先级最低,主要是因为被SHARED_WRITE互斥,但如果只有SHARED_READ则他们的优先级是兼容的。

如果看元数据锁名字比较懵,可以查看mysql意向锁的兼容互斥表。

名称类型优先级说明
SHARED_UPGRADABLE共享升级锁0一般在执行DDL时在on-line情况下会产生该锁
EXCLUSIVE排他锁X1一般在执行DDL时会产生该锁
SHARED_NO_READ_WRITE排他锁X1执行lock tables xxx write产生该锁
SHARED_WRITE意向排他锁IX2一般执行DML的更新语句 或 select ... for update产生该锁
SHARED_READ意向共享锁IS2.5select ... lock in share mode产生该锁(8.0版本以后使用select...for share)
SHARED_READ_ONLY共享锁S3执行lock tables xxx read产生该锁

所以在对表做DDL操作时,需要注意元数据锁的情况,避免事务长期持有元数据锁或在长事务执行时进行DDL操作,这样很容易阻塞该表的后续操作,而如果客户端有重试机制时,随着重试次数增多可能会打满数据库的连接,从而影响整个数据库。当然在目前版本中已经有了online DDL的支持,优化DDL操作时进行锁降级成读锁,在DDL过程中减小影响,但online DDL第一步仍然是需要获得元数据写锁,如果在第一步就卡住,结果和本次模拟操作是一样的,会影响后续操作。


所以上面语句执行完成后,id 42开启了事务执行了查询,此时先申请到了MDL读锁(也就是意向共享锁IS),并持有该锁,因为并没有提交。id 43开启了事务执行了查询,此时也可以申请到MDL读锁,所以他的查询语句是可以正常执行的。id 44对表结构进行了修改,需要申请MDL写锁,此时与id 42和 id 43互斥,无法得到写锁,所以他会被卡住,进入锁等待。而id 45只是查询该表,申请MDL读锁即可,与id 42和 id 43并不冲突,但是排在他前面id 44是写锁等待,而它只能排在id 44后面得到锁,所以被互斥,进入锁等待。

但在实际环境中,我们从上图能获得的信息是id 44、id 45进入了锁等待,但是并不知道是哪个session持有这个元数据锁。这时我们可能需要performance_schema库下的四张表metadata_locks、threads、events_statements_current及events_statements_history。

events_statements_current记录了所有在线session执行的最后一条语句

events_statements_history记录了所有在线session执行语句的历史记录(默认每个session记录10条数据,由全局参数performance_schema_events_statements_history_size决定,如果session下线则相关记录会自动被删除)

threads表用来关联processlist_id及thread_id

metadata_locks表记录了元数据锁的信息

在开始之前需要开启metadata_locks的监控,执行如下语句:

mysql > UPDATE performance_schema.setup_instruments set enabled='YES' WHERE NAME = 'wait/lock/metadata/sql/mdl';


现在开始查找具体是哪个session持有该锁,打开监控后首先要查找的表是 metadata_locks,结果如下:

观察输出:

第1行:表示thread_id 68 持有testok的元数据读锁(lock_status为granted)

第2行:表示thread_id 69 持有testok的元数据读锁(lock_status为granted)

第3-6行:表示thread_id 70分别加了全局意向排他锁,test数据库的意向排他锁,表空间testok的意向排他锁,这是由于我们在执行alter table命令时需要额外加的锁,元数据锁也是从树状态结构一级一级加下来的,全局>数据库>表空间>表本身,保证每一个层级的操作权限。为什么DDL操作需要加这些锁,试想以下情况,执行flush tables with read lock去做一些备份的事情,如果此时执行alter table而不判断全局层的锁信息,会直接在表上尝试去加元数据排他锁(写),然而发现上面已经有了共享锁(读),则直接进入了锁等待,根据上面说的情况,会阻塞后面的查询请求。而首先尝试在全局层加意向排他锁时,发现无法获得,则在全局层就报错了,回退。而不影响表的操作。其中第5行在testok表上加了shared_upgradable共享升级锁,这个和mysql的online DDL特性有关(如想了解可以自行查找相关信息,后续也会写一下)。

第7行:表示thread_id 70在testok表上申请了元数据排他锁,但是pending了,就是上面看到的锁等待。

第8行:表示thread_id 71在testok表上申请了元数据共享锁,但是也pending了。

第9行:是查询metadata_locks表产生的元数据共享锁,忽略。


经过以上的查找,我们了解了目前thread_id 68 69持有testok的元数据读锁,而thread_id 70 71在等待这个读锁,这时已经找到了“带着面具”的元凶了,接下来需要把面具撕下来,看看它到底是谁。

查找threads表,以其中一条数据为例:

通过该表我们可以将thread_id与processlist_id联系起来,也可以与thread_os_id联系起来(在操作系统中执行top -H -p [mysql_pid])

至此就找到了thread 68 69 对应的processlist id 42 43就是持有该锁的session.

同时我们可以通过events_statements_current、events_statements_history两张表查看这两个session执行哪些语句导致了锁没有释放。

首先是events_statements_current,可以看出thread 68 69最后执行的语句正是上面列表中的select语句,但这并不是不释放锁的原因,前面已经说了事务完成后会将锁释放掉

所以还需要查看events_statements_history,观察下表,以thread_id 69为例,按照event_id排序,发现select的上一个事件是begin开启了事务,但是并没有commit,至此就回溯到了根本原因。


接下来就是如何处理:

1.如果session的客户端还健在的话,可以直接执行commit

2.如果session的客户端已经挂了,执行kill processlist_id

3.调整lock_wait_timeout锁超时等待时间,让超时的事务自动回滚。(该值默认值是一年....) 


最后还要补充一个相关问题,id 44和id 45在本次实验中肉眼观察是一起完成的,实际上他们即不是一起完成的,也不是id 44的写操作先完成,在去执行id 45的查询操作。而是id 45的查询操作先完成,id 44的DDL操作后完成。

可以实验一下,如果把id45执行的语句变成与id 42 43相同会出现什么情况?

这个问题与online DDL有关 ,将在《mysql锁系列之MDL元数据锁之三》中进行说明

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mysql锁系列之MDL元数据锁之一 的相关文章

  • 【C语言 Linux系统开发 视频课程学习笔记】

    学习的课程在b站 xff1a 史上最强最细腻的linux嵌入式C语言学习教程 李慧芹老师 感谢李老师 xff01 感谢up主 xff01 本篇博客只是收集一下学习过程中遇到的函数和其他知识点 xff0c 并不会详细展开 某个函数的具体情况还
  • pthread线程私有数据TSD 几点测试结果

    更加详细的内容查看man手册或百度 xff0c 这里只是几个实际测试的结果 仅代表实验现象 xff0c 并不考虑实现原理 pthread key t key可以定义为全局变量 xff0c 全局变量属于所有线程共有的 在不同的线程中可以用pt
  • 【muduo库】server端流程图

    1 首先是根据陈硕老师的muduo库手册p11的类图 xff0c 结合自己的学习所得画的一个更详细的流程 xff0c 使用IO线程池与计算线程池 xff08 1 xff09 计算线程中 xff0c task 调用TcpConnection
  • std::bind实现在类外访问类私有成员函数

    span class token macro property span class token directive hash span span class token directive keyword include span spa
  • 树莓派(linux)安装scipy

    这里写目录标题 成功案例失败案例1 xff08 使用pip直接安装 xff09 失败案例2 xff08 使用pip安装依赖 xff09 命令安装yum使用alien 失败案例3 xff08 whl 43 setup py安装 xff09 查
  • 计算机的基本组成

    一个完整的计算机系统包括硬件系统和软件系统两大部分 xff1a 硬件系统 xff1a 是我们肉眼所见的实体 如 xff1a 电源 显示器 主机箱等 软件系统 xff1a 是我们使用的程序 xff0c 如 xff1a 微信 QQ音乐 浏览器等
  • pycharm关闭拼写检查

    pycharm默认会对函数名 xff0c 类名进行拼写检查 xff0c 不符合规则的会有一些提示和警告 xff0c 虽然不会影响程序运行 xff0c 但是看着还是比较不爽 xff0c 所以写一下关闭拼写检查的方法 打开pycharm xff
  • ROS基础——tf相关

    service和srv 我们有一个节点A会计算出右臂逆向关节运动学坐标 xff0c 我们有一个节点B xff0c 不会经常用到 xff0c 但是偶尔会用到节点A的这个坐标 假设我们用主题来通信 xff0c 那么我们的节点A要不停的来发布消息
  • EPICS的学习过程

    在此之前 xff0c 最好先学习下Linux系统的基本操作 一 了解什么是EPICS 了解EPICS base Channel Access IOC OPI 的概念 高能所内网可参考这些材料 xff1b 打开USPAS xff0c 熟悉其大
  • CentOS 7下ArchiveViewer的安装与使用

    1 下载 安装jdk 下载安装包https www oracle com java technologies downloads java8 xff1b 解压 xff1b 将 JAVA HOME bin路径添加到 PATH中 注意 xff1
  • CentOS7 安装 Archiver Appliance 的 Grafana服务

    1 安装 Grafana 7 采用rpm的安装方式 xff1a span class token function wget span https dl grafana com enterprise release grafana ente
  • AA中策略文件的使用

    一 AA策略文件 AA中关于存储策略设置的文件主要有两个 xff1a policies py archappl properties 每个appliance只有一个archappl properties和policies py文件 xff0
  • AA的管理

    1 AA的整体代码结构 AA代码的设计遵循了MVC模式 xff0c 将模型层 xff08 数据端 xff09 视图层 xff08 web客户端 xff09 控制层分离 数据端 xff08 M xff09 利用StoragePlugin接口建
  • CentOS 7下 VNC 服务的配置和开启、常见问题

    文章目录 1 X server Xvnc 和 VNC serverX Window SystemX ServerX ClientX Window ManagerDisplay ManagerX Window启动方式方式一 xff1a sta
  • AA部署中,修改Context属性造成的问题

    此处利用了https github com jeonghanlee epicsarchiverap env将AA安装在 opt epicsarchiverap 下 xff0c 并以系统服务的方式启停 问题产生原因 地球人都知道 xff0c
  • CentOS 7 下安装 Olog-es(Phoebus-olog)

    介绍报告 Olog es 服务端安装包 GitHub Olog phoebus olog Online logbook for experimental and industrial logging web服务端安装包 GitHub Olo
  • 视频监控系统安装和使用过程中的常见问题

    1 视频卡顿 花屏 当已确定POE供电距离在何时范围内时 xff0c 有可能是网线接线不规范或是网线损坏导致 对于POE供电距离较远 网络带宽较大的 xff0c 尽量连接在POE交换机的红口 xff08 红口保障 xff09 2 NVR的初
  • 关于CIDR地址的计算方法

    CIDR无类域间路由 xff0c 打破了原本的ABC类地址的规划限定 xff0c 使用地址段分配更加灵活 xff0c 日常工作中也经常使用 xff0c 也正是因为其灵活的特点使我们无法一眼辨认出网络号 广播地址 网络中的第一台主机等信息 x
  • EPICS CA请求能否成功的影响因素

    1 子网和广播域 子网掩码和广播域互为互补的网段 例如 xff1a 10 0 2 235的掩码为255 255 0 0 xff0c 则它所在的子网为10 0 0 0 xff0c 广播域为10 0 255 255 xff1b 192 168
  • 服务器采购和选型

    1 CPU 双路CPU xff0c 0号位和1号位 xff0c 只要0号位CPU正常 xff0c 服务器就能工作 xff0c 若1号位CPU故障 xff0c 服务器会报警 若0号位CPU故障 xff0c 1号位CPU正常 xff0c 服务器

随机推荐

  • CentOS 7自定义系统服务(以Phoebus-Olog为例)

    需要开启的服务 xff1a MongoDBElasticSearchPhoebus Olog后端服务Phoebus Olog web client前端服务 配置系统服务的方式 xff1a systemd 把spring boot项目配置为L
  • 在未联网的计算机中部署 yum 源和 EPICS 环境

    1 基本背景 EPICS 软件仓库 xff1a 192 168 206 234 8888 安装方式 xff1a yum 2 配置跳板机 跳板机功能 xff1a 借助ssh 隧道服务进行端口转发 xff0c 使未联网的计算机能够访问软件仓库
  • 在未联网计算机中部署Archiver Appliance(以Rocky Linux 8系统为例)

    由于计算机未联网 xff0c 而利用 epicsarchiverap env 工具进行安装的过程中需要一些联网下载安装包的操作步骤 xff0c 因此以下会给出相应的解决方法 总体思路就是 xff1a 对于一般性网址如 GitHub 等 xf
  • CentOS 7 / Rocky Linux 8 / Windows 10 系统启动 Chrony/NTP 服务

    本文内容 背景介绍1 Chrony NTP 的联系与区别2 关于 Chrony NTP 服务端 客户端的概念3 Chrony 核心组件 CentOS 7 Rocky Linux 8 系统启动 Chrony 服务1 服务状态查询2 服务配置3
  • 前端基础知识——CSS

    CSS CSS 基于 HTML 中的父子元素思想 CSS 有很多类似 Word 的排版功能 xff08 颜色 字体 文字环绕等 xff09 的属性 相关语法说明 xff1a 基本语法 xff1a 选择器 span class token p
  • GitLab的使用

    简介 xff1a Git xff0c GitHub与GitLab有什么区别 xff1f 官方网站 xff1a https docs gitlab com ee topics git 常用命令和使用方式 xff1a 看完这篇还不会用Git x
  • Archiver Appliance 事务处理流程

    当 Archiver Appliance 开始运行后发生了什么 xff1a mgmt服务 xff1a config DefaultConfigService java span class token function initialize
  • Archiver Appliance 建立集群时可能出现的问题

    0 背景知识 AA 集群中的各个节点 xff0c 完全是分布式结构 xff0c 并不存在主从关系 各个节点共享完全相同的 xff1a PVTypeInfo 数据库表PV查询权限和结果 xff08 在某一节点上查询所有 PV xff0c 也能
  • 关于python的新特性函数注释(定义函数时使用“:”及“ ->”符号)

    刷题的时候发现有的题目函数定义格式类型是这样的 xff1a def lengthOfLongestSubstring self s str gt int 这种定义方式完全没明白啥意思 xff0c 于是经过一番查找 xff0c 大体意思如下
  • Rocky Linux 8 安装实时内核

    方法一 xff1a yum 安装 在 etc yum repos d 目录下新建一个Rocky8 rt repo安装rt内核和相关工具 span class token function sudo span yum span class t
  • ununtu docker

    移除老版本 Docker sudo apt get remove docker docker engine docker io containerd runc 1 Tips xff1a 如果第一步你这里报了如下错误 xff1a E Coul
  • 如何确认当前使用的.net 版本 及 C# .net VS 版本之间的对应关系

    如何确认当前使用的 net 版本 及 C net VS 版本之间的对应关系 方法1 打开此电脑 xff0c 在地址栏中输入 systemroot Microsoft Net Framework 现在看到的就是目前使用的 net 版本 方法2
  • nuxt 获取不到localStorage,使用cookie持久化

    nuxt项目中在store和plugins的js文件里使用localStorage会报错 解决方案 xff1a 1 安装 cookie universal nuxt span class token function npm span i
  • 数据库连接报错提示connection is being used

    数据库连接报错 xff1a connection is being used 解决办法 xff1a 1 在已经保存的连接上上编辑 xff0c 测试连接成功 xff0c 但是点击连接就会一直提示 connection is being use
  • VsCode中git路径的设置(window系统)

    VsCode中git路径的设置 xff08 window系统 xff09 首先电脑里已经安装好了git并已经把git添加到环境变量中去了 xff08 这有部分在之前的帖子中有讲过 xff09 找到你的电脑里的git路径 先找到你的git安装
  • Qt报错汇总

    1 DirectShowPlayerService doRender Unresolved error code 0x80040266 IDispatch error 102 使用Qt的MediaPlayer控件时报的错 原因 xff1a
  • ubuntu18.04 ros 安装 gazebo9

    三 Gazebo安装 如果前面安装ros 的时候安装了gazebo 这里进行卸载 xff08 1 xff09 sudo apt get remove gazebo xff08 2 xff09 sudo apt get remove libg
  • CMake 常用总结一:CMake 单个文件目录

    引言 CMake 实践帮助我们对 CMake 有一个系统全面的了解 xff0c 并且有大量示例以供参考 xff0c 至少在实际项目中可以让我们有能力看懂并修改项目中现有的 CMake 阅读完 CMake 实践文档 xff0c 认为自己的任务
  • 面试(opencv)

    作者 xff1a 孙兔子 xff08 本人 xff09 链接 xff1a 面试题 xff08 opencv xff09 讨论帖 牛客网 来源 xff1a 牛客网 12 xff09 形态学梯度 复制代码 1 2 3 4 5 6 7 8 9 1
  • mysql锁系列之MDL元数据锁之一

    基础材料 xff1a centos7 5 mysql 5 7 24 当mysql运行一条SQL语句时 xff0c 在你预期的时间内 xff0c 没有完成时 xff0c 我们都会登陆到mysql数据库上想查看是不是出了什么问题 xff0c 通