ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

springboot启动耗时分析

springboot启动耗时分析

一、 简介

项目优化,首先要定位慢在哪里。记录下几个方法。官方的ApplicationStartup的实现类,BufferingApplicationStartup,FlightRecorderApplicationStartup,以及第三方利用ApplicationStartup的工具。对比下来,直接用工具更加直观,也更方便。

二、官方实现的ApplicationStartup 接口

Spring Boot 提供了BufferingApplicationStartup、FlightRecorderApplicationStartup两种实现,也支持自定义实现该接口。

2.1 BufferingApplicationStartup

记录启动时各阶段的耗时。

使用方法

  1. 修改启动类
publicstaticvoidmain(String[]args){SpringApplicationapp=newSpringApplication(SpringbootApplication.class);// 核心:设置缓冲区大小(比如记录最近 4096 个步骤)app.setApplicationStartup(newBufferingApplicationStartup(4096));app.run(args);}
  1. 打印日志
@AutowiredprivateBufferingApplicationStartupstartup;@GetMapping("/an")publicvoidgetAnalyzer(){@AutowiredprivateBufferingApplicationStartupstartup;@GetMapping("/an")publicvoidgetAnalyzer(){StartupTimelinetimeline=startup.getBufferedTimeline();// 2. 计算总耗时System.out.println("应用总启动耗时: "+timeline.getStartTime().toString());// 3. 遍历具体的启动步骤(找出最耗时的步骤)timeline.getEvents().forEach(event->{longduration=event.getDuration().toMillis();StartupStepstartupStep=event.getStartupStep();// 只打印耗时超过 600ms 的步骤if(duration>100){if("spring.beans.instantiate".equals(startupStep.getName())){for(StartupStep.Tagtag:startupStep.getTags()){if("beanName".equals(tag.getKey())){System.out.println("耗时步骤: "+startupStep.getName()+":"+tag.getValue()+" 耗时: "+duration+" ms");}}}else{System.out.println("耗时步骤: "+startupStep.getName()+" 耗时: "+duration+" ms");}}});}}
  1. 日志如下

从日志中可以看到关键步骤的耗时,以及每个 bean 的创建时间。

2.2 FlightRecorderApplicationStartup

记录每个bean创建的细节

使用方法

1、修改启动类

publicstaticvoidmain(String[]args){SpringApplicationapp=newSpringApplication(SpringbootApplication.class);// 核心:设置缓冲区大小(比如记录最近 4096 个步骤)app.setApplicationStartup(newFlightRecorderApplicationStartup());app.run(args);}

2、添加jvm参数
java -XX:StartFlightRecording:filename=recording.jfr,duration=60s -jar demo.jar

3、启动项目,启动成功会本地会生成文件 recording.jfr
4、查看内容

为什么没有内容,我也不知道。
试了几个不同方法都不行。谁知道的教教我。

三、自定义ApplicationStartup

无,有这个功能。但是不需要会。已经有现成的工具了,下面介绍

四、外部工具

目前只了解到spring-startup-analyzer,后面收到再补充

4.1 spring-startup-analyzer

它的核心思路是在启动过程中挂载自定义ApplicationStartup实现,收集所有StartupStep的耗时数据,再在启动结束后汇总成可视化报告,因此对业务代码基本无侵入。
相比 Spring Boot 自带的ApplicationStartup,spring-startup-analyzer 提供的信息更全面:不仅能看单个 bean 的创建时间,还能做数量统计、方法耗时统计和 jar 包加载统计,适合排查「启动慢到底慢在哪」这类问题.

使用方法

  1. 下载最新版本的 jar 包(或直接 clone 源码后本地打包)。
    下载链接:https://gitcode.com/gh_mirrors/sp/spring-startup-analyzer
  2. 解压后有五个文件夹,应用在lib,log有启动日志
  3. 在启动命令中通过-javaagent挂载该 agent,
java-javaagent:/path/to/spring-startup-analyzer.jar\-jaryour-application.jar

idel 中可在vm option中添加

5. 应用启动完成后,agent 会自动生成分析报告,并在控制台打印报告文件的访问地址

6. 打开报告页面,即可查看各阶段耗时、bean 创建明细、方法调用统计和 jar 加载情况。

页面说明

1、指标数据,总耗时,总bean数,总jar包,引入未使用的包,类加载器(不知道干啥的)

2、bean耗时排序,展示耗时最长的bean,支持过滤。

3、启动时序图

3、调用方法统计

方法名,次数,耗时,占比
展开详情

一些其他配置

-Dspring-startup-analyzer.app.health.check.endpoints=http://127.0.0.1:8081/actuator/health
手动指定健康节点,

总结

工具好用一点,
能找到最慢的几个类esbAppHeadResourceResolver
braveHttpServerHandler,需要优化的话可以重点关注

杂记

esbAppHeadResourceResolver 看了下代码,会重新扫描项目下包,找到配置了对应注解的类。缓存到内存中。时间几乎花在重新扫描上。可以的话,这个地方能优化下。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进