单个接口的性能调优

最近一个项目快上线了,用的是springcloud微服务,数据库是MySQL,持久层是mybatis,测试在进行性能压测的时候,有一个微服务的接口一压就挂,于是领导安排我去优化。我看了性能单,30多万的数据量,50的并发接口就挂掉了。

   1、首先了解接口代码,里面并没有复杂的业务逻辑,是一个普通的分页查询,根据前台传入的参数查询出结果,对结果进行了一次遍历判断,然后新加一个字段。最后返回前台。用的是pageHelper插件进行的分页。然后查看sql语句,就是:select * from info_table where park_code = '10034' and incident_level = 'A' order by open_date 。看了下日志打印有问题,入参日志在controller层打印了,在service层又打印相同的日志,而且最不合理的是将结果集一股脑打印出来,果断去掉。

   2、代码了解了之后先简单判断,最大的问题估计就是出在查询上面,把查询语句拿出来单独执行了下,1.42秒。检查表索引,发现索引都加上了。然后是pageHelper插件,网上了解一下,它是字段sql拼接limit,大部分人表示性能很慢,而且给出了建议。于是按照建议进行尝试,不再使用pageHelper,自己手动分页,修改查询语句,select a.* from info_table as a INNER JOIN  (select id from info_table where park_code = '10034' and incident_level = 'A' order by open_date limit 1, 10) on b where a.id = b.id; 运行一下300多毫秒,比以前快了1秒多。修改完成之后,使用jmeter本地压测,并发100,压测时间10分钟,接口正常,查询参数第1页,3000页,31000页,平均响应时间1.26秒,1.46秒,1.78秒。于是把代码部署到服务器。想着这样也就差不多了,把代码部署上去,然后等着测试去压测。

   3、本以为就此告一段落,结果第二天测试告诉我结果说服务器上面100并发压测居然要5.74秒,还是不达标,这下就不淡定了,居然还这么慢,不过好在不会出现接口压挂的事情,说明大方向没错,然后对代码再次进行了解析,只剩下一个遍历的逻辑了,按理来说分页查询出来的数据也就10条,遍历判断一下,然后在结果集里面增加一个字段应该是很快的,仔细看下这个遍历到的业务逻辑,询问了下当时做这个接口的开发人员,说是这个是开发完之后加的,要求根据时间判断一下数据是否为新数据,增加一个标识让前台展示。虽然很好奇为什么前端在展示的时候不能直接判断一下就好,非得我们后台多此一举给它增加一个字段,但事已至此也没办法,于是把这个判断挪到sql里面,在sql 里面增加一个case when 语句,于是sql 就变成这样 select a.*,CASE WHEN  open_date > DATE_ADD(NOW(), INTERVAL -5 MINUTE) THEN 1 ELSE 0 END AS is_new  from info_table as a INNER JOIN  (select id from info_table where park_code = '10034' and incident_level = 'A' order by open_date limit 1, 10) on b where a.id = b.id;测试结果比上次快了700多毫秒,平均响应时间在5秒以内,勉强达标。

4、后面分析:本地与测试相差这么多,估计内存占了大部分,然后free -m 查看下内存,top查看下占内存最高的那个,ps -ef | grep 查看下,发现内存参数最大2G,启动就占了1.5G,jstat -gcutil 查看下GC记录,发现在压测的时候YGC很频繁,10分钟内22次,平均一次0.7秒多,FGC一次。设置Xmn参数可能是个选择,适当可以增加下内存。也可以使用memory analysis tool工具具体分析下内存的使用情况,这里就不做太多的说明了。

总结一下:自己写的代码自己优化很容易陷入原有的老套路,很难发现自己的问题,最好叫别人帮忙分析。pageHelper虽然很方便,但性能差,不建议使用,分页最好公司统一封装。日志是用来方便差错的时候看的,做到关键的地方才打日记,日志记录内容要精、简、洁。代码中最好减少new 的对象,或减少对象的生命周期。最后一个Jmeter使用提示:当压测error出现的话,如果本地程序运行正常,不妨看下图形结果是什么原因引起的,本地的话Address already in use : connect 的原因居多,可以通过修改操作系统注册表来解决:1、打开注册表:regedit
2、找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters。3、新建 DWORD值,name:TcpTimedWaitDe,value:30(十进制) ——> 设置为30秒(默认240)。4、新建 DWORD值,name:MaxUserPort,value:65534(十进制) ——> 设置最大连接数65534,然后重启下电脑就可以了。
 

你可能感兴趣的:(java)