上周五,经过Grafana监控,线上环境忽然出现CPU和内存飙升的状况:git
可是看到网络输入和输入流量都不是很高,因此网站被别人攻击的几率不高,后来服务器负荷居高不下,只能保存dump文件进行分析,并一台一台服务器进行从新启动(还好你们周五下班了)shell
既然服务器在某个时间点出现了高负荷,因而就先去找一开始出现问题的服务器,去找耗时的服务,例如我当时去找数据库耗时的服务,因为上周的日志已经被刷掉,因而我大体描述一下:数据库
[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文件进行分析,调查是什么请求占用了大内存:app
观察了该对象的引用树,右键选择【class_ reference】,查看对象列表,和观察GC日志,定位到具体的对象信息。工具
经过日志以及dump文件,都指向了某个文件导出接口,接着在代码中分析该接口具体调用链路,发现导出的数据不少,并且老代码进行计算的逻辑嵌套了不少for循环,计算效率低。post
查询了该用户在这个接口的所调用的数据量,须要查询三个表,而后for循环中大概会计算个100w+次,致使阻塞了其它请求,线上的服务器CPU和内存使用状况一直飙升。性能
在看到该业务在git提交记录是我上一年实习期写的时候,个人心里是崩溃的,当时对业务不熟悉,直接循环调用了老代码,并且也没有测试过这么大的数据量,因此GG了。
而后我就开始作代码性能优化,首先仔细梳理了一下整个业务流程,经过增长SQL查询条件,减小数据库IO和查询数据量,优化判断条件,减小for嵌套、循环次数和计算量。
对比新老代码所占用的CPU和内存状态
优化前:
优化后:
经过上述优化以后,计算1w条数据量进行导出,在老代码须要48s,新代码也要8s
固然,因为这些数据是本地开发环境新增长的,与出现OOM问题的用户数据量还有些差异,但经过优化后的代码,已经在数据库查询的时候就过滤掉不少无效的数据,在for循环计算前也加了过滤条件,因此真正计算起来起来就下降了不少计算量。
恩,本身优化好了,还要等测试爸爸们测试后才敢上线,此次要疯狂造数据
在开发一开始的时候,都没有考虑到性能问题,想着知足需求就完成任务,但数据量一大起来,就有可能出现这些OOM问题,因此之后开发时,须要考虑一下几点:
万元预算玩新机 还有沈大妈的表情真好玩,直接拿来用了~