前提
这篇文章以Spring AOP为例,介绍如何快速定位执行效率较低的方法,从而解决服务运行较慢的问题。如果不是很了解Spring AOP的小伙伴,可以先看一下我的这篇文章:Spring学习之AOP,然后再回来继续看这篇文章。
背景
最近线上项目总是收到客户发来的邮件,吐槽有一些动作要等好几十秒才能有反应,问我们是不是项目出什么问题了。看到邮件的第一反应就想到可能有一些方法执行的时间太长了,导致用户的等待时间过长。所以要找到是哪些方法执行时间较长,才可以知道怎么去解决和优化。
定位执行时间较长的方法
- 我想到的方法是:
使用切面来打印方法的执行时间
。因为这种方法最简单,不用在每个方法开头的地方加开始时间,在每个方法结束的位置加结束时间和总用时时间。 - 代码如下
- 首先定义一个注解
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface TrackingTime { }
- 然后写一个切面
@Component @Aspect @Slf4j public class TrackingTimeAspectj { @Pointcut("@annotation(xxx.xxx.xxx.aop.annotation.TrackingTime)") public void trackingTimePointCut() { } @Around("trackingTimePointCut()") public Object trackingTimeAdvice(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); String methodName = joinPoint.getSignature().toLongString(); log.info( "Start execute method (" + methodName + ") at "+CalendarUtil.now().toString()); Object result = joinPoint.proceed(); log.info("Call method (" + methodName + ") used time:" + (System.currentTimeMillis() - startTime)); return result; } }
- 在可能会出现问题的方法上加上
@TrackingTime
这个注解,类似这样子@TrackingTime public List<Class> save(){ // TODO }
- 最后查看log,就可以很清晰的看到每个方法执行总用时,从而快速定位到问题所在。比如这个截图的效果,看到这个方法执行了接近20s,那么执行慢的方法找到了,接下来就要去考虑如何优化这个方法。
- 首先定义一个注解
解决方案
仔细看了一遍这个方法,发现问题有两个:
- 在创建order的时候,数据量过大,没有采用异步的方法执行
- 保存数据的时候,频繁的链接数据库
那么对应的解决方案就是:
- 采用异步加载数据
- 减少与数据库的链接次数,采用批量处理的方法