实际项目中的一个OOM和事务的问题

问题描述

线上代码如下:

  1. 先加上一个数据库行锁

  2. 执行业务操作

  3. 最后释放这个行锁

@Transactional(rollbackFor = Exception.class)

void method(){

try{

add db lock

doBiz();

}finally{

release db lock

}

}

实际遇到了 doBiz() 导致OOM了,导致数据库行锁没有释放,结果其它用户执行method方法全部失败。

问题排查

首先如上代码因为一直以来都是好的,没有遇到问题,而报错是 **DUPLICATE KEY**错误(在add db lock方法中,拿个表设置了unique key,插入相同的会报错)。

另外因为线上是很多用户操作的。

所以:直接去arthas trace该方法,然后顺便去看doBiz()方法有没有重复加锁的逻辑,且doBiz()方法是耗时的;另外还去数据库看了是否锁加成功了,即数据库有没有记录。发现都没有

然后排查到的几个现象,这个时候还没有人准确看doBiz()的异常

  1. 联系dba查看可以看到很多加锁的sql操作在等待队列中

  2. arthas trace 加锁报错了 MySQLTransactionRollbackException: Lock wait timeout exceeded,try restarting transaction

  3. 部分可以看到释放锁但是报错Communications link failure。

所以是加锁失败,然后又一直重试,一直失败。(所以去数据库查询的时候没有找到记录,然后因为很简单的sql,所以怀疑锁没有释放,去找重复加锁和释放锁为什么没有执行,结果原因在这里)。另外发现了释放锁有问题,则机器肯定也有问题了。

随后又看了机器的各个log,发现了OOM异常。所以结论是:在一个事务中,业务代码超时且OOM异常了,导致事务一直没有提交,等待锁超时,然后又一直重试。

随后改写代码加日志,验证猜想。所以这也说明平时日常工作中重要地方加日志的重要性质(然后走了一次机器发布重启,当时主要是排查也没有想到这个)

@Transactional(rollbackFor = Exception.class)

void method(){

try{

add db lock

doBiz();

}catch(Exception e){

logger.error("xxx", e)

}finally{

logger.warn("release lock");

release db lock

}

}

测试发现有测试例子是没有执行finally的释放锁方法的


顺便也说下OOM的问题,是select了数据库中的大字段,大量内存占用处,一般这个大纪录字段是单个记录才需要查询的; 当扫描了所有记录,且也select这个字段导致出现OOM。所以spring mybatis 结合查询的时候,不要什么时候都select所有字段。

相关推荐
MAGICIAN...3 小时前
【Redis】--持久化机制
数据库·redis·缓存
我真的是大笨蛋3 小时前
JVM调优总结
java·jvm·数据库·redis·缓存·性能优化·系统架构
步步为营DotNet5 小时前
5-2EFCore性能优化
数据库·性能优化·.net
2501_920047036 小时前
Redis-集群
数据库·redis·bootstrap
半夏陌离6 小时前
SQL 拓展指南:不同数据库差异对比(MySQL/Oracle/SQL Server 基础区别)
大数据·数据库·sql·mysql·oracle·数据库架构
旋转的油纸伞7 小时前
SQL表一共有几种写入方式
数据库·sql
半夏陌离7 小时前
SQL 入门指南:排序与分页查询(ORDER BY 多字段排序、LIMIT 分页实战)
java·前端·数据库
isyoungboy7 小时前
SQL高效处理海量GPS轨迹数据:人员gps轨迹数据抽稀实战指南
数据库·sql
敬业小码哥7 小时前
记一次:mysql的json及json数组使用组合使用
数据库·mysql·json
练小杰8 小时前
【Mysql-installer-community-8.0.26.0】Mysql 社区版(8.0.26.0) 在Window 系统的默认安装配置
数据库·sql·mysql·adb·配置文件·mysql安装·关系型数据库