将一个接口响应时间从2s优化到 200ms以内的一个案例

简介: 将一个接口响应时间从2s优化到 200ms以内的一个案例

一、背景

在开发联调阶段发现一个接口的响应时间特别长,经常超时,囧...

本文讲讲是如何定位到性能瓶颈以及修改的思路,将该接口从 2 s 左右优化到 200ms 以内 。

二、步骤

2.1 定位

定位性能瓶颈有两个思路,一个是通过工具去监控,一个是通过经验去猜想。

2.1.1 工具监控

就工具而言,推荐使用 arthas ,用到的是 trace 命令

具体安装步骤很简单,大家自行研究。

我的使用步骤是,先最终待研究的函数的最外层:

trace com.xxx.service.impl.AServiceImpl refresh

其中耗时最多的子函数会被标红色

Affect(class-cnt:2 , method-cnt:2) cost in 525 ms.
`---ts=2020-0X-0Y 13:33:18;thread_name=DubboServerHandler-127.0.0.1:20880-thread-36;id=24e;is_daemon=true;priority=5;TCCL=com.mmm.WWWClassLoader@4362d7df
    `---[1761.834357ms] com.xxx.service.impl.AServiceImpl$$EnhancerBySpringCGLIB$$e3cd7543:refresh()
        +---[0.017066ms] com.xxx.service.impl.AServiceImpl$$EnhancerBySpringCGLIB$$e3cd7543:$jacocoInit()
        `---[1761.00347ms] org.springframework.cglib.proxy.MethodInterceptor:intercept()
            `---[1757.647111ms] com.xxx.service.impl.AdServiceImpl:refresh()
                +---[0.006629ms] com.xxx.biz.yyy.service.impl.AServiceImpl:$jacocoInit()
                +---[0.004073ms] java.util.Collections:singletonList()
                +---[1709.203302ms] com.yyy.service.impl.AServiceImpl:refreshSomeThings()
                `---[48.135719ms] com.yzzzz.service.impl.AServiceImpl:createSurvey()

继续再 trace 耗时最多的子函数。

trace com.yyy.service.impl.AServiceImpl refreshSomeThings

最终定位到最影响耗时的函数上,继续往下跟。

最后发现造成性能瓶颈的函数是一个网络请求,单次请求大概 100多毫秒。

为了避免调用的数据量太大,项目中采用分批调用的方式,但是每个批次太小,导致请求次数过多。

假设请求 N 次(如 10次),每次请求 M毫秒(如 200ms),总耗时就是 N*M (2000)毫秒。

2.1.2 猜想

如果开发经验足够丰富,大致可以猜出哪些接口可能存在性能问题。

最常见的有:

  1. 慢 SQL 会是性能瓶颈,主要原因是没有命中索引。
  2. 发送远程数据请求(RPC 远程调用、HTTP 远程调用)。
  3. I/O 操作等。

最常见的是在循环中执行 SQL或者网络请求。

然后审查一下自己的代码发现 SQL 查询部分都可以命中索引,调用链路上有一个函数最终会调用 HTTP 请求,而且是在一个循环里。

因此最有可能成为造成接口延时的是底层依赖的 HTTP 请求。

2.2 解决

既然 HTTP 请求是性能瓶颈,那么要尽量减少请求,或者让请求由串行改为多线程并发/并行。

减少网络请求的次数,可以将多个请求合并成一个批量接口(或者增加批量请求的每个批次的大小)。

这里的批次甚至可以使用动态配置,根据情况动态修改。

将串行改为并行可以使用 CompletableFuture 来实现,具体参见:《Java 数据分批调用接口的正确姿势》

最终一个接口从1 s - 2 s降低到了 200 ms 以内。

3、总结

很多人不愿意学习 arthas ,如果不去学习不去了解,遇到可以用上的场景想不起来去用。

另外大家可以积累下开发过程中常见的性能瓶颈的原因,以便未来遇到性能瓶颈是可以快速排查和解决问题。

最后大家在开发阶段或测试阶段,多看错误日志,多关注接口的响应时长等,尽早排除问题,尽早做优化。

希望本文对大家开发能够有帮助。

如果我的文章对你有帮助,欢迎关注,点赞评论!! 在这里插入图片描述
相关文章
|
存储 网络协议 网络安全
RTSP协议抓包及讲解(三)
RTSP协议抓包及讲解
580 1
|
数据安全/隐私保护
【鸿蒙软件开发】文本输入(TextInput/TextArea)
【鸿蒙软件开发】文本输入(TextInput/TextArea)
1858 0
|
开发工具 数据安全/隐私保护 UED
Uniapp 微信登录流程解析
Uniapp 微信登录流程解析
695 0
|
7月前
|
缓存 自然语言处理 搜索推荐
大模型上线前,我们到底该怎么测?一份来自一线的检查清单
本文分享大模型对话功能上线前的实战测试经验,直击“无标准答案、状态无限、结果不可复现、判断主观”四大难点,提炼出覆盖功能、性能、安全、体验的六类测试清单及红黄绿三色上线准入标准,助力同行少踩坑、稳上线。
|
运维 安全 测试技术
云服务器还是物理服务器?企业如何根据需求做出正确决策
在数字化转型的浪潮中,企业的基础架构选择至关重要。当业务发展到一定阶段,“物理服务器”还是“云服务器”这个问题必然会摆在决策者面前。两者并非简单的谁替代谁的关系,而是各有优劣,适用于不同的业务场景。本文将为您全面解析物理服务器与云服务器的核心差异,助您做出最明智的选择。
|
11月前
|
人工智能 数据可视化 数据安全/隐私保护
AiPy定义智能财务分析,让数据说话!
看懂财报不只是看数据,更是读出背后的“故事”。以茅台2024年财报为例,AiPy智能分析揭示其高毛利、强净利与低负债背后的竞争优势,从高端酒战略到全链条效率,几分钟完成专业级洞察。
|
机器学习/深度学习 人工智能 自然语言处理
探索AI技术:从基础原理到实际应用的全面剖析
本文旨在为读者提供关于人工智能(AI)技术的全面了解。从探讨AI的基本概念和关键技术入手,逐步深入到AI在不同领域的应用实例,包括医疗、金融和自动驾驶等。同时,文章也详细讨论了当前AI技术面临的伦理问题和社会影响,以及可能的解决方案。最后,本文还展望了AI技术未来的发展趋势,帮助读者更好地理解这一前沿科技的现状与未来。
1306 6
|
数据采集 存储 Web App开发
轻量级爬虫框架Feapder入门:快速搭建企业级数据管道
本教程基于Feapder框架,讲解如何构建轻量级爬虫采集豆瓣电影数据。通过配置代理IP、Cookie与User-Agent,实现企业级数据管道能力,包括动态请求与信息提取(如电影名称、导演、演员等)。适合具备Python基础及爬虫原理知识的读者,提供从环境搭建到代码实现的完整流程,并分析常见错误与解决方法,助力高效开发。
942 1
轻量级爬虫框架Feapder入门:快速搭建企业级数据管道
|
算法 5G 调度
5G中的传输块(Transport Block)
【8月更文挑战第31天】
1144 1
|
SQL 存储 关系型数据库
MySQL数据库——锁-表级锁(表锁、元数据锁、意向锁)
MySQL数据库——锁-表级锁(表锁、元数据锁、意向锁)
1148 0