一次性从数据库查询大量数据导致的线上OOM事故分析及解决

目录

一、事故现场

二、分析过程

三、遗留问题


一、事故现场

监控发现线上服务挂了一台,登录服务器查询日志发现了java.lang.OutOfMemoryError: GC overhead limit exceeded,该错误表示:jvm使用大量的时间去做gc,但没有什么效果(创建了大量大对象且不回收垃圾)。异常日志中可以看到引发OOM的原因是hibernate 调用repository.findAll()导致的

二、分析过程

依然是导出hprof文件到本地使用jdk自带的jvisualvm进行分析,这次没有那么幸运可以直接通过点击跳转“查看导致 OutOfMemoryError 异常错误的线程”查到有用的线索,那就来看看有什么大对象吧

 

可以看到这个list.size竟然有159482,展开看看这个list都存着什么对象。展开查看metadata——>fields——>fullName(或者tableName和columnName),看看有没有熟悉的表和字段可以定位到是查询了哪个表的全部数据

到这里,已经排查出是查询了部门表的全部数据,再结合该时间执行的定时任务,最终找到代码位置:List<SysDepartmentMainData> departments = departmentMainDataRepository.findAll();

但是问题来了,部门数据怎么可能有15万多?该项目中的部门表是定时任务每天先清空表再同步公司主数据部门信息全量覆盖的(该方法是加事务的,所以不会有清空表后但调用主数据接口失败导致表里没数据的情况),查看公司主数据的部门表只有4千多,那这15万是怎么进来的?那就要去看一下存表的代码逻辑了,果然发现了问题,以下是问题原因和最终修复

三、遗留问题

查看大对象list中存放的对象表名和字段名与实体不一致,像被截断了一样。希望有知道原因的大神可以解惑🙏

实体中引用中
SysDepartmentMainDatasysdepartm0_
idid1_53_
deptcodedeptcode8_53_
deptleaderiddeptlea10_53_
deptnamedeptnam11_53_

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值