背??景在程序员的职业生涯中,总会遇到数据库表被锁住的情况,前几天又遇到了。由于突发业务需求,各个部门都在批量操作和导出数据,而数据库还没有读写分离。结果是:数据库中的某个表被锁定了!用户反馈系统部分功能无法使用,紧急排查,定位是数据库表被锁,然后死机。本文将向您介绍类似突发事件的故障排除和解决过程。建议点赞收藏,以备不时之需。故障跟踪用户在某功能页面报502错误,第一时间排查服务是否正常,数据库是否正常。在控制台可以看到数据库的CPU飙升,堆积了大量未提交的事务。一些交易已被长期封锁。基本定位是数据库层有问题。查看阻塞事务列表,发现存在表锁现象。本来想用控制台直接结束被阻塞的事务,但是控制台账号权限有限,于是通过客户端登录对应账号杀表锁事务,避免事态恶化。.下面我们就来说说吧。如果我们突然面临类似情况,应该如何紧急应对?解决方案设想了一个场景,这当然是一个软件工程师在职业生涯中都会遇到的场景:一个本来可以正常运行的程序突然突然被数据库的表锁住了,业务无法正常运行,那我们如何才能快速定位到哪个事务锁定了表,如何结束对应的事务?首先,最简单粗暴的方法是:重启MySQL。是的,网络管理员解决问题的神器——“重启”。至于后果,能跑得掉,就得三思了!重启可以解决锁表的问题,但是对于线上业务来说显然是行不通的。不跑路的先来看看解决方法:第一步:检查表的使用情况遇到数据库阻塞问题,首先要检查表是否在使用中。显示打开的表,其中in_use>0;如果查询结果为空,说明该表没有被使用,说明不是锁表的问题。mysql>showopentableswherein_use>0;Emptyset(0.00sec)如果查询结果不为空,例如出现如下结果:mysql>showopentableswherein_use>0;+-----------+------+--------+------------+|数据库|表|使用中|Name_locked|+---------+--------+--------+------------+|test|t|1|0|+-----------+--------+--------+------------+1行set(0.00sec)表示使用了表(测试),此时需要进一步调查。第二步:查看进程查看数据库当前进程,看是否有慢SQL或者阻塞线程。执行命令:showprocesslist;此命令仅显示当前用户正在运行的线程。当然,如果你是root用户,你可以看到所有的。上面的实践中,阿里云控制台之所以可以查看到所有的线程,猜测应该是使用了root用户,但是笔者去kill的时候却杀不掉,因为登录的用户不是root数据库帐户,不能操作另一个用户的线程。第3步:查看所有当前正在运行的事务。如果情况紧急,这一步可以跳过。主要用于检查:SELECT*FROMinformation_schema.INNODB_TRX;第四步:查看当前发生的锁。如果情况紧急,这一步可以跳过,但主要用于检查和检查:SELECT*FROMinformation_schema.INNODB_LOCKs;第五步:查询锁等待对应关系SELECT*FROMinformation_schema.INNODB_LOCK_waits;查看事务表INNODB_TRX中是否存在锁定事务线程,查看ID是否在showprocesslist的睡眠线程中。如果是,说明sleep线程事务没有提交也没有回滚,而是卡住了,需要手动kill掉。在搜索结果中,如果发现事务表中有很多任务,最好全部杀掉。第六步:kill事务执行kill命令:kill1011;相应的线程执行完kill命令后,后续的事务就可以正常处理了。对于紧急情况,通常直接操作第一、第二和第六步。MySQL锁这里介绍一些MySQL锁相关的知识点:数据库锁设计的初衷是为了处理并发问题。作为多个用户共享的资源,当发生并发访问时,数据库需要合理控制资源访问规则,而锁是用来实现这些访问规则的重要数据结构。根据加锁的范围,MySQL中的锁大致可以分为三类:全局锁、表级锁和行锁。MySQL中的表级锁有两种:一种是表锁,一种是元数据锁(MDL)。表锁在服务器层实现。ALTERTABLE等语句会使用表锁,忽略存储引擎的锁机制。表锁是通过locktables...read/write实现的,而对于InnoDB来说,一般都是使用行级锁。毕竟锁住整张表影响太大了。另一种表级锁是MDL(元数据锁),用于在并发情况下保持数据的一致性,保证读写的正确性。它不需要显式使用,访问表时会自动添加。MySQL锁表场景一种常见的表锁场景是在Waitingfortablemetadatalock状态下有事务操作。Waitingfortablemetadatalock当MySQL在进行altertable等DDL操作时,有时会出现Waitingfortablemetadatalock的等待场景。一旦altertableTableA的操作停滞在Waitingfortablemetadatalock状态,后续对该表的任何操作(包括读)都无法进行,因为它们也会在Waitingfortablemetadatalock阶段进入锁等待队列开台。如果核心表中存在锁等待队列,将会造成灾难性的后果。场景一:事务运行时间长,阻塞DDL,然后阻塞所有后续对同一张表的操作。通过showprocesslist可以看到表上有正在进行的操作(包括读)。此时altertable语句无法获得元数据排他锁,会等待。场景二:提交一个事务,阻塞DDL,然后阻塞对同一张表的所有后续操作。通过showprocesslist看不到表有任何操作,但实际上有未提交的事务,可以在information_schema.innodb_trx中查看。在事务完成之前,不会释放表上的锁,altertable无法获得元数据的独占锁。处理方法:通过select*frominformation_schema.innodb_trx\G找到未提交事务的sid,然后kill掉,让它回滚。场景三:显式事务失败操作获取了锁,没有释放。通过showprocesslist看不到表有任何操作,information_schema.innodb_trx中没有正在进行的事务。可能是因为在显式事务中,对表进行了失败的操作(比如查询一个不存在的字段),此时事务没有启动,但是失败语句获取的锁仍然有效并没有被释放。可以从performance_schema.events_statements_current表中找到失败的语句。解决方法:通过performance_schema.events_statements_current找到它的sid,kill掉session,或者kill掉DDL所在的session。总之,altertable语句是非常危险的(核心是未提交的事务或长事务造成的)。在操作之前,请确保要操作的表上没有正在进行的操作,没有未提交的事务,也没有显式事务。中的错误陈述。如果有altertablemaintenance任务在无人监督的情况下运行,最好通过lock_wait_timeout设置超时时间,避免长时间等待元数据锁。小结MySQL表锁其实还有很多其他的场景。我们在实践中尽量避免表锁。当然,这需要一定经验的支持。但更重要的是,我们一定要在发现表被锁住的情况下能够快速响应,快速解决问题,以免影响正常业务,避免事态进一步恶化。所以大家一定要收藏或记住本文的解决方法,以备不时之需,避免突发情况的盲目。
