记录一次性能优化的过程

性能优化:

一、背景
查询接口,一个复杂条件查询,符合条件的记录有17W,查询首页的100条,postman测试接口耗时在1.6-2秒不等。
(重复查询同一个条件,mongodb会将符合条件的记录加载到内存,因此后面查询会快一些,然后趋于一个比较稳定
的值1.6s 附近)

1.查看查询过程,因为是分页,需要知道总记录的条数(countByCondition,这一步耗时0.7-0.9秒,是性能瓶颈)同时
还需要查询100条记录(queryByCondition,这里迭代的时间在400-500ms不等),再加上处理时间,网络传输,总共在
1.6左右

二、优化

2.1 优化第一步:异步处理countByCondition;
每一次查询都统计一次,开销很大,串行处理由其明显;将countByCondition的动作通过另一个线程执行。最后的
效果是时间降低到0.9秒左右,因为是并行执行查询和计数,所以时间基本上接近耗时较久的操作。
2.2 优化第二步:缓存countByCondition结果;
countByCondition的结果只是统计的值,这个值用于计算总页数,而数据部分queryByCondition是从数据库取得,
不存在缓存一致性问题. countByCondition的值在一定范围内偏差一点点并没有影响,比如上面的17W数据,算出
来的页面总共1700多页,一点误差几乎无影响,所以这里可以缓存countByCondition的结果,在redis中有的话,
就从redis取,没有则按照步骤一去数据库查询。这样的结果是除了第一次没有缓存的时候需要0.9秒左右,后面都只
需要0.40-0.5s左右,测试从redis取count只需要3-6ms,忽略不计。
2.3 优化第三步骤:去除特征值减少网络传输;
大部分查询的时候,特征值并不需要参与业务中进行处理,之前没有遇到性能问题的时候,都是怎么方便怎么来,
没有在意细节,java程序从mongodb加载数据的时候需要走网络传输,实测含特征值的数据大小在35KB左右,去
除特征值在2kb左右,几乎95%的大小在特征值这个绝大部分查询场景没有用的字段上,因此增加字段过滤,从数据
库加载数据的时候,就去除对特征值字段的加载,到这一步之后,效果是加载耗时在300-400ms左右,大约减少了
100ms左右。到这一步用postman测试接口,首次在0.9s左右,后续的次数都在0.35秒左右
2.4 细节补充
1.count在redis的缓存失效时间;因为count只会影响计算得到页数,不会影响数据,所以这里一致性不算高,这里
我设置的是60秒
2.后续对于查询的数据也可以缓存,但是那样一旦有数据新增进库,就需要对缓存做更新,这里实现其实并不是很
简单,暂时没有做,后续可以做一个优化点,如果实现的话,热点数据查询到200ms以内应该可以,不过要保证强一
致性需要考虑的很多。
3.上述还未基于大数据量做验证,后面还需在真实环境中验证。
4.另外在做的过程中为了方便记录方法的耗时和记录日志,写了两个AOP的工具注解,可以参阅,

2.5 代码

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableCountTimeIntellif {

}

@Component
@Aspect
public class EnableCountTimeAspect {

    private static final LoggerUtilI LOG = LoggerUtilI.getLogger(EnableCountTimeAspect.class);

    @Around("@annotation(ect)")
    public Object doAround(ProceedingJoinPoint pjp, EnableCountTimeIntellif ect) throws Throwable {
        long begin = System.currentTimeMillis();
        Object obj = pjp.proceed();
        String methodName = pjp.getSignature().getName();
        String className = pjp.getSignature().getDeclaringTypeName();
        LOG.info(className + "." + methodName + " method elapsed time is: " + (System.currentTimeMillis() - begin) + " ms");
        return obj;
    }
}

三、待续

优化过程中使用的工具
1.异步处理过程并获得结果,Callable+FutureTask;
2.线程池执行任务,避免重复创建线程 。
3.自定义注解增强方法,并将附加功能与方法主流程解耦。
4.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值