【故障总结】CPU飙升?我写的?

过程

昨天我做的一个需求上预发布,刚上,准备让测试同学验证一下,就发现列表页刷不出来,很快,CPU飙升,报警邮件发个不停。

我当时没有怀疑是我做的功能的问题,因为我做的这个功能在测试环境已经验证过了。

但是后来leader导出堆栈日志,把导致CPU飙升的方法发出来,发现就是我写的一个功能,当时的感觉是惊呆了。

 

 

事故分析

我拿到堆栈日志,是如下一个bin文件

 

 

导入到MAT中(eclipse 的一个插件 memory analyzer).

下图是堆栈报告的一个概览。

 

Biggest Objects by Retained Size: 这项显示的是,堆栈日志中对象的大小分部。 

 

Actions下面有四项: 

Histogram:这项显示的是每个类对象的数量列表 

Dominator Tree: 列出最大的对象和它们保存的东西 

Top Consumers:按照类和包分类打印出“最昂贵”的对象。  

Duplicate classes:检测被多个类load的类 

 

Reports下面有两项:

Leak Suspects:包括一个泄露怀疑和系统概览。  

Top Components: 列出了大小超过1%的大对象报

这里我直接点击了Leak Suspects, 查看MAT给我们生成的一个泄露报告。

 

 

可以清晰的看到MAT 认为的错误点。

at com.laidian.erp.crm.handler.shopListHandler.ShopApprovalService.listByNewStatus(Lcom/laidian/erp/crm/handler/shopListHandler/ShopContext;)Ljava/util/Optional; (ShopApprovalService.java:86)

根据这个提示 我们找到代码

 

可以看到错误的代码出现在方法的最后一行。如果两个if条件都不满足,程序就到达最后一行,相当于下面代码。

@Testpublic void test2() {    LambdaQueryWrapper<DeviceOperApply> queryWrapper = Wrappers.lambdaQuery();    deviceOperApplyService.list(queryWrapper);}

我测试了一下,上诉代码对应的sql语句是:

select * from T;

相当于把整张表查出来了。在预发布环境,这张表有65万条数据。测试环境 只有1800条数据。所以在测试环境不会发现问题,在预发布环境,一下子把整张表查询出来,CPU自然会飙升了。

 

 

解决方法

将这个方法改成下面这样

 

 

事故总结

1. 首先是对MyBatis plus 的 list() 方法要有足够的认识

2. 单元测试要做好,每写一个方法最好都有对应的单元测试。如果这个方法有对应的单元测试用例,打印出对应的sql,这个问题就能在开发阶段就解决

3. 压力测试要做好。很多问题在测试环境不会出错,但是一到预发布,正式就出错了。就是因为压力测试没有做好。测试环境数据量小,很多写法不会出现问题,但是预发布、正式环境,数据量大,用户量也大,就会出现各种问题。

4. 代码QC也可以更加仔细一点。

 

原文地址:https://www.cnblogs.com/catlkb/p/13571948.html