一次生产死锁问题的处理

Posted 我爱看明朝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一次生产死锁问题的处理相关的知识,希望对你有一定的参考价值。

一次生产死锁问题的处理

场景

存储制品库maven包,有两张表meta_maven存储groupId、artifactId、version信息,meta_maven_file存储GAV下的具体文件jar、pom、sha1、meta_maven.xml。

场景1: deploy上传snapshot的maven包,用新的meta_maven.xml替换之前的,之前的删除。

场景2: 下载GAV包,检查是否有漏洞:开始更新组件状态为扫描中,从黑鸭子获取扫描结果(超长时间等待),更新组件的扫描结果,有漏洞禁止下载。

场景1伪代码:

@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITED, rollbackfor=Exception.class)
public void upload(MetaMavenFile metaMavenFile) 
   MetaMaven metaMaven = metaMavenMapper.select(metaMavenFile);
	
   Result uploadRet = metaMavenFileService.upload(metaMavenFile);	
	
  metaMaven.setModify("xxx");
  metaMavenMapper.update(metaMaven);	


@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITED, timeout = 8, rollbackfor=Exception.class)
public Result upload(MetaMavenFile metaMavenFile) 
 MetaMavenFile existMetaMavenFile = metaMavenFileMapper.select(metamavenFile);
 String filePath = fastdfsServer.upload(metaMavenFile);
 existMetaMavenFile.setStorageReference(filePath);
 metaMavenFileMapper.updateByPrimaryKeySelective(existMetaMavenFile);

场景2伪代码:


@Transactional(propagation= Propagation.REQUIRED, isolation= Isolation.READ_COMMITED, timeout = 8, rollbackFor = Exception.class)
public void download(MetaMavenFile metaMavenFile, HttpResponse response)
	mataMaven existMetaMaven = metaMavenMapper.select(metaMavenFile);
mataMavenMapper.updateCompoentStatus(existMetaMaven.getId(), ComponentStatus.SCANNING, null);
	hasSecurityExist(existMetaMaven.getId());


public void hasSecurityExist(Long metaMavenId) 
 	JSONObject scanResult = getblackDuckScanResult(metaMavenId);
 	mataMaven existMetaMaven = metaMavenMapper.select(metaMavenId);
	metaMavenMapper.updateByPrimaryKey(existMetaMavenFile);

事务执行流程

步骤事务1事务2
1beginbegin
2select * from meta_maven where id = 1
3select * from meta_maven where id =1
4update meta_maven set component_status = 1 where id =1
5update meta_maven set status = 1 where id =1
6获取黑鸭子扫描结果(超长时间等待)
7deallock detected
8update meta_maven set component_status = 2 where id = 1
9commitrollback

一般产生死锁的场景(上面的和它不一样,上面的和我们之前介绍的悲观锁发生死锁等待很像):

步骤事务1事务2
1beginbegin
2update table1 set col =1 where id =1
3update table1 set col1 = 2 where id =2
4update table1 set col1 = 3 where id = 2
5update table1 set col1 = 4 where id = 1
6deaded lockdeaded lock

报错信息

 Error updating databse, Cause: org.postgressql.util.PSQLException: ERROR: deadlock detected
 Detail: Process 322869 waits for sharelock in transaction 3523519865;
 blocked by process 369631.
Process 369631 waits foe ShareLock on transaction 3523519865;
blocked by process 369632.
 where: while updating tuple(22892,30) in relation "meta_maven";ERROR: deadlock detected
### SQL: update meta_maven set modifyer = ? where id = ?

怎么处理

我们可以看到,问题很大是出现在hasSecurityExist这个超长等待,

  1. 那么我们把这个方法的事务传播机制改为REQUIRED_NEW或者异步执行(这个逻辑支持异步执行的)
  2. 大事务拆小,设置手动声明事务的方式来提交

REQUIRED_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起,意思是创建一个新的事务,和原来的事务没有关系

处理思路;

  1. 大事务拆小,大事务可能发生死锁,如果业务允许,将大事务拆小
  2. 添加合理的索引,没有索引可能会产生表锁,增加死锁发生的概率
  3. 降低隔离级别,如果业务允许,将隔离级别调小是比较好的选择,比如将隔离级别从repeat commit 调整为 read commit.

场景2优化伪代码:


@Transactional(propagation= Propagation.REQUIRED, isolation= Isolation.READ_COMMITED, timeout = 8, rollbackFor = Exception.class)
public void download(MetaMavenFile metaMavenFile, HttpResponse response)
	mataMaven existMetaMaven = metaMavenMapper.select(metaMavenFile);
	// 处理死锁问题,这个方法单独抽出来,单独声明事务传播机制

	hasSecurityExist(existMetaMaven.getId());


@Transaction(propagation= Propagation= Propagation.REQUIRES_NEW)
public void updateCompentScaning(Long metaMavenId) 
	mataMavenMapper.updateCompoentStatus(metaMavenId, ComponentStatus.SCANNING, null);


@Transaction(propagation= Propagation= Propagation.REQUIRES_NEW)
public void hasSecurityExist(Long metaMavenId) 
 	JSONObject scanResult = getblackDuckScanResult(metaMavenId);
 	mataMaven existMetaMaven = metaMavenMapper.select(metaMavenId);
	metaMavenMapper.updateByPrimaryKey(existMetaMavenFile);

以上是关于一次生产死锁问题的处理的主要内容,如果未能解决你的问题,请参考以下文章

生产环境MySQL死锁如何监控及如何减少死锁发生的概率。

Mysql生产死锁临时解决

记录一次由于logback死锁引起的生产事故

记一次最近生产环境项目中发生的两个事故及处理方法

MySQL大无语事件:一次生产环境的死锁事故,看看我怎么排查

MySQL大无语事件:一次生产环境的死锁事故,看看我怎么排查