复盘线上的一次OOM和性能优化!

来源:r6d.cn/ZazN

上周五,发布前一周的服务器小动荡????

事情回顾

上周五,通过Grafana监控,线上环境突然出现CPU和内存飙升的情况:

但是看到网络输入和输入流量都不是很高,所以网站被别人攻击的概率不高,后来服务器负荷居高不下,只能保存dump文件进行分析,并一台一台服务器进行重新启动(还好大家周五下班了)

通过日志分析

既然服务器在某个时间点出现了高负荷,于是就先去找一开始出现问题的服务器,去找耗时的服务,例如我当时去找数据库耗时的服务,由于上周的日志已经被刷掉,于是我大致描述一下:

[admin@xxx xxxyyyy]$ grep '15:14:' common-dal-digest.log |  grep -E '[0-9]{4,}ms'
2018-08-25 15:14:21,656 - [(xxxxMapper,getXXXListByParams,Y,1089ms)](traceId=5da451277e14418abf5eea18fd2b61bf)

上述语句是查询在15:14那一分钟内,在common-dal-digest.log文件中,耗时超过1000ms的SQL服务(我上周查的是耗时超过10秒的服务)。

通过traceId去查Nginx保存的访问日志,定位在该时间点内,分发到该服务器上的用户请求。还有根据该traceId,定位到整个调用流程所使用到的服务,发现的确十分耗时…

于是拿到了该请求具体信息,包括用户的登录手机号码,因为这个时候,其它几台服务器也出现了CPU和内存负载升高,于是根据手机号查询了其它几台服务器的访问日志,发现同一个请求,该用户也调用了很多次…

使用mat进行dump文件分析

通过mat工具对dump文件进行分析,调查是什么请求占用了大内存:

观察了该对象的引用树,右键选择【class_ reference】,查看对象列表,和观察GC日志,定位到具体的对象信息。

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

查询了该用户在这个接口的所调用的数据量,需要查询三个表,然后for循环中大概会计算个100w+次,导致阻塞了其它请求,线上的服务器CPU和内存使用情况一直飙升。


代码进行性能优化

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

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

通过jvisualVM进行对比

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

优化前:

优化后:

通过上述优化之后,计算1w条数据量进行导出,在老代码需要48s,新代码也要8s,不过这是大数据量的情况下,实际用户的数据没有这么多,所以基本上满足了线上99%的用户使用。

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

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


开发注意点

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

  • 梳理设计流程

  • 考虑是否有性能问题

  • 与产品经理商量控制查询条件,减少查询的范围

  • 与数据库交互时,减少无效的查询,合并查询和合并更新操作

  • 减少for循环,尤其注意for循环嵌套问题!

  • 调用老代码要看注意=-=


吐槽

果然每次看之前写的代码,都有种要si要si的感觉.


往期推荐

不要再用main方法测试代码性能了,用这款JDK自带工具


Socket粘包问题的3种解决方案,最后一种最完美!


MySQL为Null会导致5个问题,个个致命!


关注我,每天陪你进步一点点!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阅读源码的 4 个绝技,我必须分享给你!

为什么要阅读源码?1.在通用型基础技术中提高技术能力在 JAVA 领域中包含 JAVA 集合、Java并发(JUC)等, 它们是项目中使用的高频技术,在各种复杂的场景中选用合适的数据结构、线程并发模型,合理控制锁粒度等都能显著提高应用程序的…

innerHTML、innerText和outerHTML、outerText的区别

1、区别描述如下: innerHTML 设置或获取位于对象起始和结束标签内的 HTMLouterHTML 设置或获取对象及其内容的 HTML 形式innerText 设置或获取位于对象起始和结束标签内的文本outerText 设置(包括标签)或获取(不包括标签)对象的文本innerText和outerText在获取时是相…

Socket粘包问题终极解决方案—Netty版(2W字)!

作者 | 王磊来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)上一篇我们写了《Socket粘包问题的3种解决方案》,但没想到评论区竟然炸了。介于大家的热情讨论,以及…

Java高质量代码之 — 泛型与反射

在Java5后推出了泛型,使我们在编译期间操作集合或类时更加的安全,更方便代码的阅读,而让身为编译性语言的Java提供动态性的反射技术,更是在框架开发中大行其道,从而让Java活起来,下面看一下在使用泛型和反射需要注意和了解的事情 1.Java的泛型是类型擦除的 Java中的泛型是…

Redis 消息队列的三种方案(List、Streams、Pub/Sub)

现如今的互联网应用大都是采用 分布式系统架构 设计的,所以 消息队列 已经逐渐成为企业应用系统 内部通信 的核心手段,它具有 低耦合、可靠投递、广播、流量控制、最终一致性 等一系列功能。当前使用较多的 消息队列 有 RabbitMQ、RocketMQ、ActiveMQ、K…

c struct 对齐_C中的struct大小| 填充,结构对齐

c struct 对齐What we know is that size of a struct is the sum of all the data members. Like for the following struct, 我们知道的是, 结构的大小是所有数据成员的总和 。 对于以下结构, struct A{int a;int* b;char c;char *d;};Size of the st…

超3000岗位!腾讯产业互联网新年大扩招!

虽然离春节仅剩 1 个月的时间,大厂依旧没有停止招人。就在上周,腾讯官宣新年大扩招,放出 3000 多个岗位需求!我们查看了腾讯的招聘数据发现,除了大量招聘运营人员,你猜,他们还在批量招聘什么岗位…

骚操作,IDEA防止写代码沉迷插件 !

当初年少懵懂,那年夏天填志愿选专业,父母听其他长辈说选择计算机专业好。从那以后,我的身上就有了计院深深的烙印。从寝室到机房,从机房到图书馆,C、C、Java、只要是想写点自己感兴趣的东西,一坐就是几个小…

css属性 content

对css一直没有很系统得学习过,练习得也不是很多,纯小白.今天在写一个页面的时候,遇到一个问题,就是如何让外面的盒子适应里面的盒子大小,完美地把小盒子包在里面. 由于里面是一个列表 ul,为了让元素横排,我使用了float:right这个属性,所以列表悬浮了.如图: 其实当然可以直接给外…

一文汇总 JDK 5 到 JDK 15 中的牛逼功能!

前言JDK 16 马上就要发布啦(预计 2021.3.16 日发布),所以在发布之前,让我们先来回顾一下 JDK 5-15 的新特性吧,大家一起学起来~Java 5 新特性1. 泛型泛型本质是参数化类型,解决不确定具体对象类型的问题。L…

Tomcat 6.0 简介

本片翻译来自:http://tomcat.apache.org/tomcat-6.0-doc/introduction.html 介绍 无论是开发者还是tomcat管理员在使用前都需要了解一些必要的信息,本篇简单的介绍tomcat中的一些术语和概念。比如context是web应用的意思。CATALINA_HOME 在文档中&#x…

Docker部署SpringBoot的两种方法,后一种一键部署超好用!

作者 | LemonSquash来源 | cnblogs.com/npeng/p/14267007.html1.手工方式1.1.准备Springboot jar项目将项目打包成jar1.2.编写DockerfileFROM java:8 VOLUME /tmp ADD elk-web-1.0-SNAPSHOT.jar elk.jar EXPOSE 8080 ENTRYPOINT ["java","-Djava.security.egdfi…

UISwitch 添加 标签

给UISwitch添加一个标签。左右滑动时候出现开关标签内容。 代码: // // UISwitchJGLabel.h // JGSwitch // // Created by sl on 15/4/11. // Copyright (c) 2015年 Madordie. All rights reserved. // // // 说明: // 1.给UISwitch添加开关标…

爱了!蚂蚁开源的“SpringBoot”框架,新增了这6项功能...

SOFABoot 是蚂蚁金服开源的基于 Spring Boot 的研发框架,它在 Spring Boot 的基础上,提供了诸如 Readiness Check,类隔离,日志空间隔离等等能力。在增强了 Spring Boot 的同时,SOFABoot 提供了让用户可以在 Spring Boo…

PUC的完整形式是什么?

PUC:大学预科/污染控制/个人解锁码 (PUC: Pre University Course / Pollution Under Control / Personal Unlock Code) 1)PUC:大学预科课程 (1) PUC: Pre University Course) PUC is an abbreviation of the Pre University Course. It alludes to an in…

过滤器VS拦截器的4个区别,看完豁然开朗!

Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。但它们之间又有很大区别,所以本文磊哥就带大家全面了解一下什么是过滤器?什么是拦截器?以及二者有什么区别…

分布式ID生成的9种方法,特好用!

前言业务量小于500W或数据容量小于2G的时候单独一个mysql即可提供服务,再大点的时候就进行读写分离也可以应付过来。但当主从同步也扛不住的是就需要分表分库了,但分库分表后需要有一个唯一ID来标识一条数据,数据库的自增ID显然不能满足需求&…

8051 管脚定义_8051微控制器的引脚说明

8051 管脚定义8051微控制器的引脚说明 (Pin Description of 8051 Microcontroller) Pins from 1-8 1-8针 Port 1: The pins in this port are bi-directional and can be used for input and output. The pins are individually controlled; some are used for input while ot…

android 事件分发

2019独角兽企业重金招聘Python工程师标准>>> 文章来源于CSDN http://blog.csdn.net/lanhuzi9999/article/details/26515421 转载于:https://my.oschina.net/lhjtianji/blog/398998

对象复制的7种方法,还是Spring的最好用!

日常编程中,我们会经常会碰到对象属性复制的场景,就比如下面这样一个常见的三层 MVC 架构。当我们在上面的架构下编程时,我们通常需要经历对象转化,将业务请求流程经历三层机构后需要把 DTO 转为DO然后在数据库中保存。当需要从数…