一、背景
上周五,其他项目组违背了周五不能发版的规定,18:30
下班前两个系统发了新版
19:30
运营反馈系统很卡,华为云CPU
100%报警
二、解决思路
因为应用服务器不同项目组是共用的,影响到我负责的系统,所以我也帮忙排查
第一直觉判断应该是内存泄露或大对象
因为数组内存分配在Oracle
JDK8
空间必须是连续的(IBM
J9
不是),如果大对象无法申请到足够的内存,那么就会OOM
检查周五提交的代码记录,发现select *
和where
条件名字数据在20W
,并且使用Stream.collect
产生新集合,局部变量一直持有原集合,预估数据量在40W
左右,并且接口属于数据同步类型的,基本上每2分钟一次拉取,因为大数据查询耗时,算上并发时客户端数量在20个左右,峰值数量在800W
,这仅仅是其中一个数据同步接口,如果应用服务器其他接口内存申请触发GC
,处理延迟,峰值更高,由于都存在引用,full gc
也无法回收内存,故JVM
抛出OOM
先回滚了代码,定位问题大概用了20-30分钟
三、思考
抛开代码code review
和开发的问题,谈谈大对象的优化
通常大对象发生的场景
- 数据导入导出
- 文件服务器
- 批处理任务 ......
优化的方法
- 可以每次取小量,使用offset记录偏移量,在循环中处理
- 在使用完后的数据,后续不用时,对局部变量赋值为null,这种在处理耗时较长场景提升较大
- 尽量不要查出数据在应用中聚合统计
- 流处理(mybatis支持流和游标返回数据)
原理就是寻找大数据小内存的通用解