问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

一次接口的性能优化之旅

创作时间:
作者:
@小白创作中心

一次接口的性能优化之旅

引用
1
来源
1.
https://www.cnblogs.com/Jcloud/p/18121663

在项目开发过程中,接口响应慢是一个常见的问题,它不仅影响用户体验,还可能降低系统的吞吐量。本文通过一个实际案例,分享了如何通过Pfinder工具进行性能诊断,以及如何通过代码优化、异步处理等手段提升接口性能。

一、现状诊断

在项目中,我们遇到了接口响应慢的问题。通过UMP诊断发现:

  • Max响应时间:10s
  • T99响应时间:1000ms
  • 经常出现可用率下降的情况

进一步使用Pfinder进行诊断,发现了以下具体问题:

  1. 循环调用RPC 120次,耗时1441ms
  2. 数据库查询耗时286ms
  3. 存在未知操作,耗时2000ms+

二、问题定位与优化

1. 解决Pfinder显示耗时不全问题

通过手动完善全程跟踪上报来解决。具体步骤包括:

  1. 集成Pfinder SDK:

    <dependency>
        <groupId>com.jd.pfinder</groupId>
        <artifactId>pfinder-profiler-sdk</artifactId>
        <version>1.2.2-FINAL</version>
    </dependency>
    
  2. 使用@PFTracing注解

  3. 定位问题并进行代码分析

经过分析发现,代码中存在大量数据处理耗时问题:

这段代码的目的是从一个名为waveInfos的字符串列表中,筛选出已经包含在另一个名为sendDPackageCodes的字符串列表中的元素,并将这些重复的元素放入一个新的列表repeatResult中。然后,它从waveInfos中排除这些重复的元素,将剩余的元素放入另一个新的列表showPackages中。这两个列表最终被用于前端显示或进一步处理。简而言之,这段代码的作用是去重并筛选出尚未处理的数据。

通过现象查看此处代码耗时占总耗时进一半左右,因此判断集合数据非常多,导致数据计算耗时较长。通过日志打印发现:

  • waveInfos=3000+
  • sendDPackageCodes=7000+

可以看出两个集合因为数据过大导致耗时较长。

2. 代码优化:使用Set进行处理

优化效果:2000ms -> 6ms

3. 解决RPC批量调用问题:使用JSF异步调用

同步异步方案比较
特性
异步调用
同步调用
优势
提高系统的并发性能
简单直观
提高系统的响应速度
错误处理方便
节约资源
-
劣势
复杂性
阻塞线程
可读性差
响应速度慢
JSF异步调用使用
  1. 如果存在同步bean,为了不影响同步bean可以注入新的异步bean。需要注意:jsf 这边相同接口 别名 最多支持3个

    <jsf:consumer id="xxx" interface="xxx"
                  protocol="jsf" alias="xx" timeout="xxx" retries="0" check="false">
        <jsf:method name="方法名称" async="true"/>
    </jsf:consumer>
    
  2. 使用RpcContext调用,返回CompletableFuture对象

    public CompletableFuture<CommonDto<PageDto>> queryWaybillDetailByBusinessIdByAsync() {
        // 发起方法请求
        return RpcContext.getContext().asyncCall(() -> xxxxAsyncApi.method());;
    }
    
  3. 调用处任意地方,获取future返回结果,需要指定超时时间

    public <T> T getResultDefaultTimeOut(CompletableFuture<T> future) {
        try {
            return future.get(10, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }
    

优化效果:1400ms -> 200ms

三、最终效果和未解决问题

问题
优化前
优化后
方案
总耗时
3800ms
500ms
-
rpc循环调用
1400ms
200ms
JSF异步调用(N次耗时变一次最大耗时)
数据笛卡尔积处理
2000ms
6ms
list包含操作变set包含操作
数据库操作
100ms
100ms
数据库批量查询,此期不处理
未知操作
150ms
150ms
非业务代码,怀疑是sql查询后结果处理,目前无法跟踪和处理,此期不处理

四、总结

接口性能优化是一个涉及多个方面的过程,需要从代码层面、数据库、缓存、异步处理等多个维度进行优化。在这个过程中,我们需要不断诊断瓶颈、尝试优化手段,并结合实际情况进行调整。希望通过本文的分享,大家能掌握接口性能优化的方法和技巧,提高接口性能,提升用户体验。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号