当前位置: 首页 > 科技观察

实战分享-你知道这个死锁是怎么产生的吗?

时间:2023-03-21 22:06:42 科技观察

Part1后台锁作为MySQL知识体系的主要部分之一,是每个DBA都需要学习和掌握的知识。锁保证了数据库数据在并发场景下的一致性,锁冲突也是影响数据库性能的因素之一。在锁冲突中,有一个经常被讨论的经典场景:死锁。最近刚遇到一个典型的死锁案例。本文将基于此案例做详细的分析和拆解。Part2问题由于innodbenginestatus会记录最近一次死锁的详细信息,所以案例现场的信息是可以完整获取的。用户针对这个死锁问题提出了疑问:数据不是在同一行更新的,使用了不同的索引。为什么会出现死锁?(以下细节已脱敏)死锁的两条语句如下:UPDATEtbl_deadlockSETcol1=1,col2=1,update_time=1603685523WHERE(id1=6247476)AND(id2=74354)UPDATEtbl_deadlockSETcol1=1,col2=1,update_time=1603685523WHERE(id1=6249219)AND(id2=74354)简化后的MySQL死锁信息如下:=======================================2020-10-2612:14:307fd2642f5700INNODBMONITOROUTPUT======================================...省略...------------------------LATESTDETECTEDDEADLOCK----------------------------2020-10-2612:12:037FD2846ED700***(1)交易:交易1795660514,Active0secstartingIndexexreadMmysqltables3,locked3lockwait4lockstruct(s),shepsize1184,3771781781781781781827822222222222222222222222222。21.0.15usernameupdatingUPDATEtbl_deadlockSETcol1=1,col2=1,update_time=1603685523WHERE(id1=6247476)AND(id2=74354)***(1)WAITINGFORTHISLOCKTOBEGRANTED:RECORDLOCKSspaceid8575pageno286947nbits104tableindex`deid2`ofdlock`.`tbl_deadlock9`5lo605`trxid17ck_modexwaitingrecordlock,heapno429physicalRecord:n_fields2;compactformat;infobits00:len4;hex00012272;hex00012272;asc;1:len4;;1:len4;hex00721f45;hex00721f45;ascre;ascre;;)MySQLthreadid21905203,OSthreadhandle0x7fd2846ed700,queryid178279443172.21.0.15usernameupdatingUPDATEtbl_deadlockSETcol1=1,col2=1,update_time=1603685523WHERE(id1=6249219)AND(id2=74354)***(2)HOLDSTHELOCK(S):RECORDLOCKSspaceid8575pageno286947nbits1048index`id2`oftable`deadlock`。;1:len4;hex00721fe3;ascr;;Recordlock,heapno431PHYSICALRECORD:n_fields2;compactformat;infobits00:len4;hex00012272;asc"r;;1:len4;hex0072218f;ascr!;;...省略很多Recordlock...***(2)WAITINGFORTHISLOCKTOBEGRANTED:RECORDLOCKSspaceid8575pageno344554nbits120index`PRIMARY`oftable`deadlock`.`tbl_deadlock`trxid1795660513lock_modeXlocksrecbutnotgapwaitingRecordlock,heapno9PHYSICALRECORD:n_fields44;compactformat;infobits00:len4;hex00722663;ascr&c;;...省略无关的两Line...3:len4;hex005f5434;asc_T4;;4:len4;hex00012272;asc"r;;...省略多行...***WEROLLBACKTRANSACTION(1)...省略...Part3原因分析首先简单了解一下死锁的几个要素:1、互斥条件:一种资源一次只能被一个进程占用,MySQL的锁机制自然满足这个条件2、请求和保持条件:当资源请求被阻塞时,持有的资源不会被释放,当MySQL没有触发死锁回滚,没有进入lockwait_timeout时满足这个条件。3.非剥夺条件:获取的资源在用完之前不能被强行剥夺。MySQL的加锁MySQL的机制自然有这个条件。4、循环等待条件:在几个进程之间形成一个头尾相连的循环等待资源关系,通常表现为有向环。由于MySQL的锁机制,只需要判断两条SQL语句的锁是否在循环等待,那么死锁条件就会成立。接下来详细分析MySQL中记录的死锁信息。首先观察死锁的事务细节:LOCKWAIT4lockstruct(s),heapsize1184,3rowlock(s).......20lockstruct(s),heapsize2936,40rowlock(s)可以很明显的发现这两条语句涉及到一个很多数据行。用户的问题:data更新不是同一条线其实是个误区。理论上“循环等待:彼此持有对方需要的锁”,这种典型的死锁场景是可能存在的。接下来,重点放在更细节的信息上:***(1)WAITINGFORTHISLOCKTOBEGRANTED:RECORDLOCKSspaceid8575pageno286947nbits1048index`id2`oftable`deadlock`.`tbl_deadlock`trxid1795660514lock_modeXwaitingRecordlock,heapno429PHYSICALRECORD:n_fields2;compactformat;infobits00:len4;hex00012272;asc"r;;1:len4;hex00721f45;ascrE;;......***(2)WAITINGFORTHISLOCKTOBEGRANTED:RECORDLOCKSspaceid8575pageno344554nbits120index`PRIMARY`oftable`deadlock`.`tbl_deadlock`trxid1795660513lock_modeXlocksrecbutnotgapwaitingRecordlock,heapno9PHYSICALRECORD:n_fields44;compactformat;infobits00:len4;hex00722663;ascr&c;;...省略不相关的两行...3:len4;hex005f5434;asc_T4;;4:len4;hex00012272;asc"r;;...省略多行...网友提出的问题:索引也不同,为什么会发送死锁?事实上,二级索引上的记录锁最终会被加到主键上。这个很容易理解,如果在二级索引上,通过搜索商品表的商品名称索引(二级索引)来查找“iphone12”,并对这行数据加锁,锁定商品的详细数据"iphone12"OK,如果其他事务可以通过查找主键来修改这一行数据,那显然是不行的。因此,在这种情况下,虽然死锁信息中记录的索引名称不同,但争锁的条件是成立的,即:trx1通过二级索引对主键进行锁操作,而trx2对主键进行锁操作其他二级索引中的主键。在索引上获得了锁,但是无法获得主键锁,因此进入等待状态。因此,只需要定位到具体的锁数据,找到循环等待的逻辑关系,就可以完成整个案例分析。参考上面引用的信息,发生死锁的行的具体信息记录在0:len4;等信息中。十六进制00722663;ascr&c;;.trx1中记录的锁等待信息是二级索引id2,因为id2是单行索引,所以只有两行信息,0和1,0代表具体的行id2,1为主键。使用十六进制转换工具将其转换为十进制,可以找到对应的数据如下:pk=7479109andid2=74354然后查看trx2中记录的信息。在锁等待方面,记录的信息是主键,所以这个地方会有完整的表数据,过滤掉无效数据后,剩下三行:0是主键,3是id1,4是id2.base转换后对应的数据如下:pk=7480931andid1=6247476andid2=74354可以看出trx2等待的锁,id1和id2刚好满足trx1的查询条件。在trx2持有的锁信息中,第一个正是trx1等待的:trx2持有的锁那么这个死锁案例的具体场景可以用下面的定向环图例来说明:deadlocklegendsofar,case本次死锁分析完毕,从最开始分析死锁的成立条件,到具体锁内容的解读,最后完成死锁的有向循环图例。其实,如果你自己观察这个死锁的有向环图例,你会发现这两条语句使用了两个单列索引。进一步思考一下,如果将这两列构建成一个联合索引,这种死锁情况是不是真的呢?也许它不会发生?Part4总结,对于死锁问题,只需要根据四个条件一步步过滤分析即可。通过解读死锁场景的详细内容,可以准确还原整个死锁的原因和涉及的数据行。当然,在实际的业务环境中,可能会出现更复杂、更隐蔽的死锁情况,但无论多么隐蔽、多么复杂,死锁分析的思路和步骤都是大同小异的。关于专栏《腾讯云数据库专家服务》是腾讯云数据库技术服务团队维护的社区专栏,内容涵盖各种数据库的实际案例、最佳实践、版本特性等。