mysql运维脚本与个人理解

参考文章

《mysql show full processlist 详解》

《MySQL性能分析之show processlist及information_schema.processlist详解》

《Mysql报Deadlock found when trying to get lock; try restarting transaction问题解决》

《MySql Lock wait timeout exceeded该如何处理》

《关于MySQL的lock wait timeout exceeded解决方案》

写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。

一、关于死锁

        操作系统对死锁的完整定义为:多个进程在运行过程中因争夺某一临界资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。

        我们经常遇到的锁问题有2种:

        (1)Deadlock found when trying to get lock; try restarting transaction       

        (2)lock wait timeout exceeded; try restarting transaction

          第1种异常是Mysq明确规定的死锁,在官方文档中有非常详细的解释,这里截取一部分,有兴趣的朋友可以移步这里查看 《Deadlocks in InnoDB》

     

mysql运维脚本与个人理解_第1张图片

          很多文章里习惯把第2种异常称为死锁,但这其实有问题的,我们从他的英文名翻译来

看,lock wait timeout exceeded,锁等待超时,也就是说,事务A先加了锁后,事务B也想加锁,

如果事务A是排他锁,事务B就只能等待,当这个等待时间超过阈值(可通过mysql全局变量查看,

SHOW VARIABLES LIKE 'innodb_lock_wait_timeout')时,就会抛出此异常。说不对的原因在于

锁等待超时 ,可能是因为慢sql等原因。在我司的内部博客中也有DBA做了专门的说明。

 不过有1点相同,就是这2中情况都使得我们的事务执行异常(try restarting transaction)

 造成锁问题的可能原因很多,这里简单列举下:

        (1)执行DML操作没有commit,再执行删除操作就会锁表。
        (2)在同一事务内先后对同一条数据进行插入和更新操作。

        (3)表索引设计不当,导致数据库出现死锁。
        (4)长事物,阻塞DDL,继而阻塞所有同表的后续操作。

  补充: 既然提到了锁,那必然要介绍下Mysql中锁(这里只做简单介绍,实际规则要复杂许多)

        (1)表锁,在InnoDB与MyISAM中都有实现,执行粒度是整张表,说人话就是

事务A加了表锁,事务B在获取到锁前就动不了这张表

        (2)行锁,只在InnODB中实现了,行锁的粒度单行记录,就是锁事务A锁住了某条记录,

事务B可以动这张表的其他记录,但不能动这条记录,行锁的出现提高了mysql的并发能力。(注

意,行锁的前提是命中索引,即这条sql利用到了某个索引才行)

        (3)间隙锁,在可重复读(Repeatable read)级别下,使用当前读模式会存在幻读的隐

患,即锁的粒度是行记录的级别,我们虽然不能改这些记录但是可以往表里插入数据。就导致了事

务中前后读取结果不一致,为了解决这一问题就有了间隙锁,将加了行锁的这些记录再两两之间加

上锁,使得新的相关记录无法插入,这就是间隙锁。(这是当前读模式,与之对应的快照读则采用

了多版本并发控制(MVCC)来实现)。

          这部分可以看我这篇博客:《mysql之事务、锁、隔离级别与MVCC》

二、锁问题的处理方法

       1.  查询事务表并kill相关线程

select * from information_schema.innodb_trx

             有几个重要的列我们需要了解

             trx_id:事务id
             trx_status:当前的事务状态,running、lock wait、rolling back or commtting.
             trx_started:事务的开始时间
             trx_requested_lock_id:事务等待的锁的id(如果事务状态不是lock wait,这个字段是null)
             trx_wait_started:事务等待的开始时间
             trx_mysql_thread_id:MySQL找那个的进程id,与show processlist中的id值相对应
             trx_query:事务运行的SQL语句
             trx_operation_state:事务当操作的类型如updating or deleting,stating index read等

     死锁问题本地没复现出来,所以网上找了张图,当作参考。

mysql运维脚本与个人理解_第2张图片

         我们可以看到标红的这条事务处于lock wait锁等待状态,当我们在运维时遇到这种就可以使

用 kill  +  trx_mysql_thread_id 来杀死(图中例子具体脚本为 kill 738178711)。

         同时,我们也可以根据trx_started即事务的开始时间判断是否有长事务阻塞等情况。

        2. 查看当前sql运行情况

        上面介绍了事务的处理方案,但开头我们也介绍了,不只是事务有锁,我们的DML(insert、

delete、update)操作也会产生锁(锁等待时间通过show variables  like 'lock_wait_timeout' 可以

查看,我们发现比事务锁阈值参数少了个开头的InnoDB,这也强调了只有InnoDB中才有事务,而锁

则广泛存在于各种存储引擎中

       mysql为我们提供了下面这个管理工具来查看所有sql的运行情况。

show full processlist

mysql运维脚本与个人理解_第3张图片

        id:线程id
        user:显示单前用户,如果不是root,这 个命令就只显示你权限范围内的sql语句。
        host:显示这个语句是从哪个ip的哪个端口上发出的,可以用来追踪出问题语句的用户。
        db:显示 这个进程目前连接的是哪个数据库。
        command:显示当前连接的执行的命令,一般就是休眠(sleep),查询(query),连接 (connect)。
        time列,此这个状态持续的时间,单位是秒。
        state:显示使用当前连接的sql语句的状态,请注意,state只是语句执行中的某一个状态, 一个sql语句,可能需要经过copying to tmp table,Sorting result,Sending data等状态才可以完成。        

        info:显示这个sql语句,因为长度有限,所以长的sql语句就显示不全,但是一个判断问题语句的重要依据。

        我们可以观察执行时间明显异常的sql,通过killd + id 将其杀死。

        注意点:
        (1)Time、Info列比较重要,Info列展示当前线程运行SQL,如果为空,
则说明当前线程为sleep状态,而Time列则代表当前状态维持的时长(s),如果Info有具体的SQL,
则代表该SQL运行时长,如果Info为空,则代表线程空闲等待时长,线程每次执行新的SQL,Time都会重新计时。

        (2)存在很多sleep状态的线程time列很大,这些sleep线程其实是因为druid连接池的原因,所以一直并未真正关闭,处于空闲等待。

       补充个小知识:mysql中每个 mysql 的连接都在一个单独的线程中运行,(所以这里

processlist叫做连接清单或者线程清单都行)我们执行kill命令实际上就是将这个线程杀死。

  关于kill的使用可以查看这篇官方文档。《kill statement》

mysql运维脚本与个人理解_第4张图片

    3.  其他辅助脚本

         除了show full processlist ,我们还可以使用information_schema.processlist来查看,好处是可以对状态维持时间排序。

select id, db, user, host, command, time, state, info
from information_schema.processlist
order by time desc 

mysql运维脚本与个人理解_第5张图片

展示的信息和show full processlist是一样的,但还有另一个好处,就是可以批量生成kill脚本,这里我生成了kill所有lock状态2分钟的脚本。

select concat('kill ', id, ';')
   from information_schema.processlist
 where command = 'Locked'
  and time > 2*60
  order by time desc 

三、根因分析

     这块内容需要对工具展示的内容有一定了解,内容较多这里这里暂不详解,条件允许可以咨询DBA。

show engine innodb status 

================================分割线===================================

2021年8月29日补全:详解文章《mysql死锁分析工具show engine innodb status》已补齐,可移步观看。

你可能感兴趣的:(mysql,mysql,数据库)