cover_image

高并发场景性能优化-剖析接口超时解决方案

Chen·Small-K 拍码场
2025年02月06日 03:18

图片

前言

在数字化浪潮汹涌的当下,信息传播和服务提供高度依赖APP、网站等线上平台,其性能与稳定性尤为关键,直接左右着用户体验和业务的顺畅推进。

一、问题现象

在日常上线发布流程中,某核心服务在发布过程中,频繁遭遇上游接口超时的棘手难题,该问题会直接导致APP相关流程短暂异常,影响用户体验,并且系统监控警报声此起彼伏,这给我们带来极大困扰。

图片

二、初步排查与怀疑

通过查看线上服务监控平台与服务日志,我们发现实例刚引入流量时,最初几个请求的接口响应极为迟缓,且涉及不同接口,而在这批接口响应成功后,后续接口响应则恢复正常。基于此现象,我们展开了初步排查:

1.硬件资源排查:查看服务的机器数量充足,同时利用监控平台查看 CPU 使用率、内存使用率、磁盘 I/O 等指标,确认服务的硬件资源满足高并发需求。

2.网络资源排查:借助监控平台查看网络带宽的使用情况以及网络延迟数据。与网络同事沟通,确认网络环境无异常。

3.接口性能排查:对接口的代码逻辑、算法复杂度、是否存在慢SQL进行审查,确定接口自身性能无问题。

4.内存泄露排查:借助监控平台与dump文件深入检查了堆内存大小、确认内存使用情况正常,不存在内存持续增长且无法释放的现象。

图片

5.JVM参数排查:检查服务配置的jvm参数与服务生效的jvm参数,验证配置的参数生效的。我们借助监控平台查看GC情况,堆内存使用情况,检查垃圾回收器的参数设置等关键指标。查看服务对应机器配置情况为2C4G,初始内存设置为2G,最大堆内存设置2G, 使用G1垃圾回收器,最大垃圾回收暂停时间为200ms。JVM 参数配置合理,能确保 JVM 能够高效稳定地运行,不存在内存不足或垃圾回收频繁而引发的性能瓶颈。

具体JVM 配置参数如下:

java -jar -Dfile.encoding=UTF-8 -server -Xms2G -Xmx2G -Xss512k -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/dump ${project.build.finalName}.jar

服务jvm配置属性截图:

图片


经过初步排查,排除了上述可能的问题,怀疑是服务的tomcat线程池初始化或数据库初始化未完成导致。

三、深入排查

1.Tomcat线程池排查

通过查看监控视图以及检查线程配置的详细数据,判断tomcat线程数是否增长正常。依据获取的数据进行分析,我们发现站点 Tomcat 初始化线程的配置,其最小值设为 100,最大值为 200。借助监控图表得以证实,Tomcat 初始化配置切实生效,且程序运行数分钟后线程数才开始增缓慢长。这一结果表明,tomcat线程池初始化并非导致接口变慢的缘由。

Tomcat线程池初始化参数配置:

java -jar -Dfile.encoding=UTF-8 -Dserver.tomcat.max-threads=200 -Dserver.tomcat.min-spare-threads=100

Tomcat线程数监控截图:

图片

2.数据库排查

首先,检查连接池的大小、获取连接的等待时间等配置参数,同时与 DBA 同事共同确认配置的合理性。经过确认,数据库连接池配置合理。然后,我们继续排查是否是接口初始化和数据库初始化导致。为了方便排查,我们需要运用 jProflier 工具(该工具详细使用教程可网上自行学习)。

第一步:本地启动站点项目,启动 jProflier 应用,在 jProflier 中选择需要观察的应用,相关截图如下:

图片

图片

图片

第二步:随机请求一个接口,在 jProflier 应用中选择 call Tree 指标,找到接口调度的指定线程,观察接口耗时详情情况。

服务日志截图:

图片

jProflier应用截图:

图片


第三步:通过使用 jProflier 对接口的耗时情况进行分析,对于相同接口的不同参数请求,通过分析发现接口的第一次调用和第二次调用耗时差异巨大。且耗时的 “重灾区” 主要集中在mybatis组件启动与数据库创建部分,这无疑证实了我们之前的猜想。相关截图及数据如下:


第一次请求分析截图:

图片

第二次请求分析截图:

图片

接口耗时情况统计:

接口总耗时mybatis组件初始化耗时数据库创建耗时
第一次请求962ms500ms300ms
第二次请求253ms6ms5ms

四、解决方案与成果

  • 确定问题原因后,那究竟要如何解决呢?我们的解决思路是在站点发布成功后拉入流量之前,对站点数据库等初始化流程进行预热。即在项目启动完成后拉入流量前调完成一次接口方法的调用,对于 springboot 项目我们通过实现 ApplicationRunner 接口的 run 方法,使得项目启动完能够立即执行接口方法调用。
    具体代码如下:
@Componentpublic class MysqlRunner implements ApplicationRunner {
private static final Logger logger = LoggerFactory.getLogger(MysqlRunner.class);

@Autowired private Controller controller;
@Override public void run(ApplicationArguments args) { try { logger.info("springboot启动后预热执行开始-------------" ); Long start = System.currentTimeMillis(); Request request = new Request(); //写死一个查询条件调度接口 request.setParmas(1); request.setLimit(1); controller.query(request); logger.info("springboot启动后预热执行结束,耗时" + (System.currentTimeMillis() - start) + "ms-------------" ); } catch (Exception e) { logger.error("springboot启动后预热执行异常-------------", e); } }}
测试接口优化前后耗时对比

优化前耗时优化后耗时
第一次请求962ms289ms
第二次请求(与第一次入参相同)253ms226ms
第三次请求(与第一次入参不同)263ms231ms

最后上线观察成果:站点发布时,上游站点再无超时告警,问题得以成功解决!

五、总结

对于高并发场景下接口超时问题优化,一般解决方案有以下五步:

1.检查硬件资源:判断服务机器是否充足,是否需要扩容。

2.检查网络资源:判断网络环境是否稳定,带宽是否充足。

3.检查jvm参数:判断是否存在内存泄露,垃圾回收是否正常,jvm配置是否合理。

4.检查接口性能:判断接口本身性能问题,是否存在慢SQL,redis初始化等问题。

5.检查服务程序:是否需要初始化预热,包括且不限于tomcat线程池初始化,数据库初始化等。

以上是本次关于高并发性能优化对应解决方案,希望本篇文章能给广大开发者带来启示和切实的帮助!如果您遇到类似问题,不妨参考我们的解决思路。也欢迎大家留言分享自己的经验和看法,让我们共同在技术的海洋中不断进步!

六、作者介绍

Chen·Small-K 信也科技后端研发

七、招聘信息


图片往期精彩内容指路


基于AI的智能测试助手

交互式营销系统:基于用户行为意图营销

WebSocket协议在作业系统的落地实践

提升跨境网络速度-在国际与国内环境中实现加速连接

Redis双活切换平台建设

阿里云多账号统一认证


继续滑动看下一个
拍码场
向上滑动看下一个