记一次MySQL死锁问题排查

问题描述

 

经销平台旧服务通过RPC调用新服务保存客户销售区域信息时,RPC频繁超时

 
 
 

问题背景

平台客户销售区域管理功能处于新旧服务迭代阶段,有部分数据需要在旧服务中通过RPC调用新服务接口来实现保存。

 
 
 
 
 
 
 

项目上线后发现功能报错,日志显示RPC超时,且报错十分频繁,通过StopWatch进行执行时间监控后,发现一条删除操作每次都需要执行10秒导致RPC接口超时。

 
 
 
 

问题排查步骤

通过阿里云ADS平台抓取SQL执行会话,发现,确实是删除语句执行非常耗时,但是本表中只有两万条数据,且是通过主键进行删除,不应该这么慢,所以猜测是数据库锁问题,但是ADS平台中显示没有任何死锁和慢SQL操作,所以决定通过手动查询INNODB日志来排查问题。

 

 

 

在数据中执行:

 
select * from information_schema.INNODB_TRX;
 

发现,当删除事务执行时,会同时出现两个事务记录,且其中一个事务权重极高,并且真正执行的删除事务处于WAIT_LOCK阶段,和ADS平台中显示的只有一个记录不相符,故猜测是这个多出的事务导致的超时问题

 
 
 
紧接着执行:
 
select * from information_schema.INNODB_LOCKS;

发现有两个事务在同时争抢数据库中同一物理扇区同一条记录的行锁,并且锁的类型都为X排它锁,超时的原因就是因为这个死锁导致的

 
 
 
 

通过单元测试调用新服务的RPC接口时,发现innodb中不会出现这种死锁的情况,且代码执行极快,故猜测应该是旧服务在调用RPC接口之前对这条记录进行了操作,提前拿到了X锁。

最终找到问题的根源在以下代码:

 

旧服务在调用RPC之前进行了一次更新UPDATE操作,然后调用了RPC,RPC接口中刚好也对这条记录进行了操作。

此时,旧服务通过事务A执行UPDATE拿到了行数据的X锁,在等待RPC执行完成后提交事务。而RPC中需要通过事务B操作这条记录所以一直在等待X锁,两个不同的事务同时获取同一个锁,所以导致了死锁,最终RPC因为一直拿不到锁导致超时。

解决方案

这个问题是因为新旧服务混合迭代过程中,因为双方代码逻辑冲突导致的,所以最后将冲突代码统一迁移至新服务中解决冲突。

posted @ 2023-08-17 10:48  Tassdar  阅读(39)  评论(0编辑  收藏  举报