记一次线上 OOM 和性能优化(下)

简介: 大家好,我是鸭血粉丝(大家会亲切的喊我 「阿粉」),是一位喜欢吃鸭血粉丝的程序员,回想起之前线上出现 OOM 的场景,毕竟当时是第一次遇到这么 紧脏 的大事,要好好记录下来。

2.3 根本原因

通过日志分析以及 dump 文件分析,都指向了某个文件导出接口,接着在代码中分析该接口具体调用链路,发现导出的数据很多,而且老代码进行计算的逻辑嵌套了很多 for 循环,而且是 for 循环调用数据库,计算效率极低。

模拟了该用户在这个接口的所调用数据量,需要查询多个表,然后 for 循环中大概会计算个 100w+ 次,导致阻塞了其它请求,由于请求未结束,java 对象无法被 GC 回收,线上的服务器 CPU 和内存使用情况一直飙升。


3 性能优化

3.1 业务、代码逻辑梳理

点开该段代码的 git 提交记录,发现是我在实习期写的时候,我的内心是崩溃的,当时对业务不熟悉,直接循环调用了老代码,而且也没有测试过这么大的数据量,所以 GG了。

66.jpg

然后我就开始做代码性能优化,首先仔细梳理了一下整个业务流程,通过增加 SQL 查询条件,减少数据库 IO 和查询返回的数据量,优化判断条件,减少 for 嵌套、循环次数和计算量。

3.2 通过 VisualVM 进行对比

官方描述:

VisualVM,能够监控线程,内存情况,查看方法的CPU时间和内存中的对象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的).

该插件不需要另外下载,在 ${JAVA_HOME}/bin 目录下就能找到,所以安装了 jdk 就能使用它~

对比了新老代码所占用的 CPU 时间和内存状态

优化前:

67.jpg

优化后:

68.jpg

通过上述优化之后,计算 1w 条数据量,进行导出成报表文件,在老代码需要 48s,新代码下降到了 8s,不过这是大数据量的情况下,实际用户的数据没有这么多,所以基本上满足了线上 99% 的用户使用。(看到这个结果时,阿粉露出了「纯洁的微笑」)

0.gif

当然,由于这些数据是本地开发环境新增加的,与出现 OOM 问题的用户数据量还有些差别,但通过优化后的代码,已经在数据库查询的时候就过滤掉很多无效的数据,在 for 循环计算前也加了过滤条件,所以真正计算起来起来就降低了很多计算量!

恩,自己代码优化好了,还要等测试爸爸们测试后才敢上线,这次要疯狂造数据!


4 技术总结

阿粉周末会自己做点饭🍚,喜欢看王刚老师的视频,觉得最后出现的 「技术总结」 很棒,让我能够快速记住重要步骤

但学习跟做饭一样,还是得经过反复看和实践才能好好记住,哼儿哈儿,大伙知道阿粉想说的是啥了吧哈哈哈)69.jpg

4.1 开发注意点

在开发初期,阿粉没有考虑到性能问题,想着满足需求就完成任务,但数据量一大起来,就有可能出现这些 OOM 问题,所以以后开发时,需要先提前考虑以下几点:

  1. 梳理设计流程
  2. 考虑是否有性能问题
  3. 与产品经理商量控制查询条件,减少查询的范围
  4. 与数据库交互时,减少无效的查询,合并查询和合并更新操作
  5. 减少 for 循环,尤其注意多层 for 循环嵌套问题!
  6. 调用老代码要注意=-=

4.2 应对故障注意点

出现问题时也不要惊慌,好好去解决它才是王道,「在解决问题中学到更多技术」

可以参考以下步骤:

  1. 保留现场,dump 堆栈信息
  2. 进行限流,对出现问题的接口进行降级
  3. 如没有降级措施,服务器本身无法快速恢复正常,联系运维重启进行恢复的同时,记录下有可能出现问题的数据,等待后面修复
  4. 日志、堆栈信息分析
  5. 定位问题并解决

5 多说两句

在定位到问题时,看到是阿粉写的,原本以为会受到批评,但领导并没有责怪我,还叫阿粉之后好好改,避免下次出现这种问题,心情很开朗,希望各位小伙伴也能遇到这种开明的领导。肯定不是阿粉的颜值高70.jpg

在这次问题排查过程中,熟悉了问题排查步骤,巩固了 jdk 工具的使用方法和流程,也加深了对业务的理解程度,果然 「遇到问题能够快速成长」

同时解决 BUG 后,阿粉的内心更开心了,下班后点了一份小碗鸭血粉丝。

各位小伙伴看完觉得有趣或者有用,来个素质三连,帮忙点个在看,让阿粉能升级吃大碗哈哈哈~

精彩回顾:

MyBatis 的 DAO 接口跟 XML 文件里面的 SQL 是如何建立关系的?

Gateway:数据报文走出局域网的必经之路

一文带你了解 Redis 的发布与订阅的底层原理

如果有人再问你 Java IO,把这篇文章砸他头上

相关文章
|
8月前
|
消息中间件 存储 Java
jvm性能调优实战 - 47超大数据量处理系统是如何OOM的
jvm性能调优实战 - 47超大数据量处理系统是如何OOM的
87 0
|
8月前
|
存储 SQL 算法
jvm性能调优 - 11J线上VM调优案例分享
jvm性能调优 - 11J线上VM调优案例分享
193 0
|
运维 监控 Java
内存溢出+CPU占用过高:问题排查+解决方案+复盘(超详细分析教程)
全网最全的内存溢出CPU占用过高排查文章,包含:问题出现现象+临时解决方案+复现问题+定位问题发生原因+优化代码+优化后进行压测,上线+复盘
2463 5
|
监控 Java
【JVM线上调优】
【JVM线上调优】
107 0
|
8月前
|
监控 数据可视化 Java
jvm性能调优实战 - 31从测试到上线_如何分析JVM运行状况及合理优化
jvm性能调优实战 - 31从测试到上线_如何分析JVM运行状况及合理优化
107 1
|
运维 监控 Java
35-JVM性能优化总结-JVM性能优化到底该怎么做?
通过之前大量的案例和工具的介绍,相信大家对于JVM优化有了一定的了解和熟悉,接下来我们将整个JVM性能优化的步骤做一个总结。
217 0
|
监控 Java Linux
大厂的OOM优化和监控方案(二)
大厂的OOM优化和监控方案(二)
大厂的OOM优化和监控方案(二)
|
Web App开发 Java Linux
【性能优化】使用Perfetto定位应用启动性能的瓶颈
本篇文章将会结合我个人对Perfetto的实际使用经历,讲解车载应用的启动时间是如何测量得到的,测量出启动时间后,我们又该如何找出其中的性能瓶颈。
1740 1
【性能优化】使用Perfetto定位应用启动性能的瓶颈
|
Arthas 存储 Java
9种OOM常见原因及解决方案
9种OOM常见原因及解决方案
1078 0
|
运维 监控 Java
记一次线上OOM和性能优化,值得借鉴!
记一次线上OOM和性能优化,值得借鉴!
246 0