高效开发与设计:提效Spring应用的运行效率和生产力 | 京东云技术团队

引言

现状和背景

Spring框架是广泛使用的Java开发框架之一,它提供了强大的功能和灵活性,但在大型应用中,由于Spring框架的复杂性和依赖关系,应用的启动时间和性能可能会受到影响。这可能导致开发过程中的迟缓和开发效率低下。优化Spring应用程序的启动速度和性能是一个重要的任务,通过分析和优化应用的初始化过程、减少不必要的依赖和组件加载、并利用异步初始化、懒加载等技术,可以显著改善应用的启动性能。这将帮助开发者提高开发效率、减少调试时间,并提供更好的用户体验。

线上的业务 jar 包基本上普遍比较庞大,动不动一个 jar 包几百 M,启动时间在10分钟级,拖慢了我们在故障时快速扩容的响应、以及本地开发调试效率。于是做了一些分析,看看 Spring 程序启动慢到底慢在哪里,如何去优化,目前的效果是大部分大型应用启动时间可以缩短 70%~80%。

主要有下面这些内容

  • SpringBean 加载耗时 timeline 可视化分析(✅)
  • SpringBean 的可视化依赖分析(✅)
  • 应用未加载的jar包(Jar瘦身)(✅)
  • 应用启动过程线程wall clock火焰图(✅)

重要性和影响

开发效率提高:较快的应用启动速度可以显著减少开发和调试的时间。开发人员能够更快地启动应用程序,进行功能测试和调试,从而提高开发效率和迭代速度。

部署和扩展效率提升:优化启动速度可以减少部署和扩展应用程序的时间和成本。快速启动的应用程序可以更快地响应负载变化,提高系统的可伸缩性和弹性。

资源利用率优化:通过减少初始化时间和优化资源加载,可以降低应用程序的内存和CPU占用率。这有助于提高服务器的利用率,并降低运行应用程序的成本。

分析工具

  • Arthas:Arthas是一个开源的Java诊断工具,可以实时监控和诊断Java应用程序。它提供了丰富的命令和功能,用于分析应用程序的性能问题,包括启动过程中的资源消耗和加载时间。
  • JVM Sandbox:JVM Sandbox是一种基于Java安全管理器的技术,用于隔离和限制Java应用程序的访问权限。它可以帮助减少启动时的资源消耗和加载时间,提高应用程序的启动速度。
  • Async Profiler:Async Profiler是一个低开销的异步Java性能分析工具,用于收集和分析应用程序的性能数据。它可以帮助你找出启动过程中的性能瓶颈,以及其他影响启动速度的问题。
  • 启动加速-异步初始化方法:异步初始化方法是一种启动加速的技术,通过将一些初始化任务异步执行,可以减少启动时间并提高应用程序的响应性。这可以通过使用线程池、异步框架或异步注解等方式来实现。
  • Spring Boot Startup Report:Spring Boot Startup Report是一个用于生成Spring Boot应用程序启动报告的工具。它可以提供详细的启动过程信息,包括每个bean的加载时间、自动配置的耗时等,帮助你分析和优化启动过程。
  • Jaeger UI: Jaeger UI是一个用于可视化和分析分布式追踪数据的工具。通过使用Jaeger UI,你可以监控和分析应用程序的启动过程,识别潜在的性能问题和瓶颈。
  • Spring Startup Analyzer:Spring Startup Analyzer是一个用于采集Spring应用程序启动过程数据并生成交互式分析报告的工具。它的目标是帮助分析Spring应用程序的启动卡点,并支持Spring Bean的异步初始化,以减少优化Spring应用程序的启动时间。该工具支持在Linux、Mac和Windows操作系统上运行,并参考了spring-boot-startup-report实现其用户界面。使用Spring Startup Analyzer,可以收集应用程序的启动过程数据,并生成可视化的HTML报告。这个报告可以帮助你分析Spring应用程序的启动性能,并找出潜在的优化机会。

Spring Startup Analyzer优化方案

借助Spring startup analyzer的能力,我们以业务线的ARK项目为例,深入研究如何优化提效Spring项目的启动过程。下面我们先观察下ARK的基本启动情况:

启动概览

  • Startup Time(s):启动时长
  • Num of Bean:初始化的Bean数量
  • Used/Total Jars:使用Jar数量/总量
  • Unused/Total Jars:未使用Jar数量/总量
  • ClassLoader Count:类加载器数量

Spring Bean初始化详情

  • Name:一级name对应着Bean的名称
  • Duration with children (ms) :Bean的引用加载时长
  • Duration (ms) :Bean本身的加载时长
  • Detail:包含类加载器、加载该Bean的线程信息(异步加载的话会有多个不同的)

SpringBean 加载耗时 timeline 可视化分析

这个观察项可以一直下探,直到Bean引用的最末级,可以看出每一级的加载时长

应用启动过程线程wall clock火焰图

如何看懂火焰图

y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。

x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。

火焰图就是看顶层的哪个函数占据的宽度最大。只要有"平顶"(plateaus),就表示该函数可能存在性能问题。

颜色没有特殊含义,因为火焰图表示的是 CPU 的繁忙程度,所以一般选择暖色调

火焰图总览

从总览图中可以看出,有三个入口函数占用百分比较大,下面分别看一下

火焰局部图1

这部分火焰图可以看出,springfox在启动过程做了很多初始化,占了大量时间,对于不需要该功能的项目,可以直接下掉

火焰局部图2

了解下spring bean 的初始化过程

从这个图中可以看出,bean的创建过程也占了很多时间

火焰局部图3

从这个图中可以看出,注册BeanPostProcessor也耗费了大量时间

应用未加载的jar包(Jar瘦身)

这一个观察项可以搜集到项目启动完之后,没有用到的Jar包

实施与优化效果

操作步骤和配置项

安装Spring Startup Analyzer

手动安装

  1. 点击realease下载最新版tar.gz包

  2. 新建文件夹,并解压

linux/mac系统可以考虑使用以下命令:

mkdir -p ${HOME}/spring-startup-analyzercd 下载路径
tar -zxvf spring-startup-analyzer.tar.gz -C 安装路径/spring-startup-analyzer

脚本安装(linux/mac)

curl -sS https://raw.githubusercontent.com/linyimin0812/spring-startup-analyzer/main/bin/install.sh | sh

脚本默认安装路径:$HOME/spring-startup-analyzer

应用启动

spring-startup-analyzer是以agent的方式启动的,所以在启动命令中添加参数-javaagent:安装路径/spring-startup-analyzer/lib/spring-profiler-agent.jar即可。

  • 以java命令行的方式启动应用,则在命令行中添加参数,例如:
java -javaagent:/Users/runner/spring-startup-analyzer/lib/spring-profiler-agent.jar \-Dproject.name=mac-demo \-Dspring-startup-analyzer.admin.http.server.port=8066 \-jar /Users/runner/spring-startup-analyzer/ARK.jar
  • IDEA中启动,则需要在VM options选项中添加:

日志文件路径:安装路径/spring-startup-analyzer/logs

  • startup.log: 启动过程中的日志
  • transform.log: 被re-transform的类/方法信息

应用启动完成后会在console和startup.log文件中输出======= spring-startup-analyzer finished, click http://localhost:xxxx to visit details. ======,可以通过此输出来判断采集是否完成。

启动时间和性能改善情况

优化之前

预发平均启动10分钟,本地无法启动,每次需求需要提交到预发环境验证,开发和发版周期比较长,且预发环境连接的生产库,不能随便造数。项目引用585个jar,其中有337个jar没用到。

慢bean分析

分析可以看到,耗时排名前面的接口都是jsf相关的加载,还有一个es相关的bean。

功能路径:Details of Method Invoke --> AbstractAutowireCapableBeanFactory.createBean

jsf启动优化

注:index=“注册中心地址”中的“注册中心地址“做了匿名,在具体场景查看自己代码中的配置

jsf的生产者的注册中心在启动的时候,会拉取一批ip,不断尝试注册jsf,在办公环境这些ip无法访问,导致启动过程一直重试

    <!-- 预发、生产的注册中心 --><jsf:registry id="jsfRegistry" protocol="jsfRegistry" index="注册中心地址"/>

在本机host里面增加jsf发布地址的host配置,下面*...* 在使用的时候替换成自己的,可以 ping test.注册中心地址 获取。“注册中心地址” 替换成上面index后面的地址

*.*.*.* 注册中心地址 

再次启动项目,时长来到185s

开启Bean懒加载

将ES的Bean初始化进行懒加载,以及开启全局懒加载,时长来到131s;

全局懒加载:

1、根据spring版本的不同,开启全局懒加载的方式可能会不相同

2、不建议生产环境开启全局懒加载,因为基本上我们的服务都是部署在k8s上的,有可能服务在伸缩的时候,在访问量大的时候,由于懒加载的配置,服务快速启动成功了,会返回给docker容器服务已经准备就绪状态,导致k8s把流量分给该服务,导致预想不到的问题。

Jar瘦身

对于应用未使用的jar包,可以谨慎剔除,在剔除的时候一个一个下,每下一个都要重复编译和启动验证是否会对项目造成影响,这是一个持续和长期的过程,Jar瘦身不仅对启动时长有收益,而且对编译提效很明显,减少了大量的Jar复制过程

最终效果

做完上述优化之后:

  • 本地能够启动和debug项目,这对开发人员来说有极大的提效。
  • 预发使用该方案进行优化之后,能够缩短项目编译以及发布的时间,对于快速验证和迭代需求有极大提效。
  • 整体启动效率提升70%~80%。
  • 在intel芯片电脑,启动速度在2min11s。
  • 在m1芯片的电脑,速度会更快,大概启动时间在90s左右。
  • 使用该思路,可以优化大部分spring以及spring boot项目,建议定期做一轮这种排查和优化。

优化关键点和方法

  • 去除未使用的jar包:定位未使用的jar包。通过分析和整理项目依赖,可以将这些未使用的jar包从应用中移除,减少编译、启动时间和资源消耗。
  • 优化慢速的Bean初始化:找到启动耗时较长的Bean。可以考虑对这些接口和Bean进行优化,例如使用延迟加载或异步加载的方式,以减少启动时的耗时。
  • 取消不需要的发布:对于本地开发环境而言,如果不需要发布jsf接口,可以在本地取消这部分的发布,以节省启动时间。
  • 开启全局懒加载:通过开启全局懒加载,可以延迟加载一些不必要的组件和资源,从而减少启动时间。确保在需要使用时才进行加载。
  • 拆分大型组件:定位加载时间较长的组件,可以考虑将其拆分成多个组件,并在启动时只加载需要的部分。这样可以减少启动时的加载时间和资源消耗。
  • 使用性能分析工具:结合之前提到的性能分析工具,如Spring Startup Analyzer、Java Profiler、VisualVM等,对应用进行性能分析。通过监测和分析应用的性能数据,可以找到性能瓶颈,并针对性地进行优化。
  • 定期进行代码优化和重构:定期审查和优化代码,识别和消除潜在的性能问题。使用优化的算法和数据结构,减少不必要的计算和循环,优化数据库查询等,以提高应用的性能。
  • 使用缓存机制:合理地使用缓存来减少对数据库或其他资源的频繁访问。通过缓存常用数据或计算结果,可以显著提升应用的响应速度和性能。
  • 并行化处理:如果有一些独立的任务可以并行处理,可以考虑使用多线程或异步机制来提高处理速度和效率。

信息补充

oracle jdk8下载地址

https://www.oracle.com/java/technologies/downloads/#java8-mac

oracle登录账号

请联系作者提供免费账号

本地redis安装

https://redis.io/docs/install/install-redis/install-redis-on-windows/

spring-startup-analyzer启动分析工具

https://github.com/linyimin0812/spring-startup-analyzer/blob/main/README_ZH.md

作者:京东健康 梁灿

来源:京东云开发者社区 转载请注明来源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/153954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang基础-面向过程篇

文章目录 基本语法变量常量函数import导包匿名导包 指针defer静态数组动态数组(slice)定义方式slice追加元素slice截取 map定义方式map使用方式 基本语法 go语言输出hello world的语法如下 package mainimport ("fmt""time" )func main() {fmt.Println(&…

循环链表2

循环链表的实现 对于数据结构中所有的结构而言&#xff0c;每一次都是用之前初始化&#xff08;处理一开始的随机值&#xff09;一下&#xff0c; 用完销毁&#xff08;不管有没有malloc都能用&#xff0c;用了可以保证没有动态内存泄漏了&#xff09;一下 而在C里面&#x…

Dubbo开发系列

一、概述 以上是 Dubbo 的工作原理图&#xff0c;从抽象架构上分为两层&#xff1a;服务治理抽象控制面 和 Dubbo 数据面 。 服务治理控制面。服务治理控制面不是特指如注册中心类的单个具体组件&#xff0c;而是对 Dubbo 治理体系的抽象表达。控制面包含协调服务发现的注册中…

PLC设备相关常用英文单词(一)

PLC设备相关常用英文单词&#xff08;一&#xff09; Baud rate 波特率Bus 总线Binary 二进制Configuration 组态Consistent data 一致性数据Counter 计数器Cycle time 循环时间Conveyor 传送Device names 设备名称Debug 调试Download 下载Expand 扩展Fix 固定Flow 流量Functio…

【LeetCode:689. 三个无重叠子数组的最大和 | 序列dp+前缀和】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

WMS系统先验后收策略

在制造业工厂的仓库管理中&#xff0c;确保物料的质量和数量是至关重要的。传统的仓库管理方式往往采用“先收后验”策略&#xff0c;即先接收物料&#xff0c;然后再进行质量检验。然而&#xff0c;这种方式存在一定的风险&#xff0c;例如不良品流入、数量不准确等问题。为了…

腾讯云服务器标准型S5实例CPU性能如何?配置特性说明

腾讯云服务器CVM标准型S5实例具有稳定的计算性能&#xff0c;CVM 2核2G S5活动优惠价格280.8元一年自带1M带宽&#xff0c;15个月313.2元、2核4G配置748.2元15个月&#xff0c;CPU内存配置还可以选择4核8G、8核16G等配置&#xff0c;公网带宽可选1M、3M、5M或10M&#xff0c;腾…

优思学院|现代质量管理实践与六西格玛方法论如何融合?

企业要解决质量问题必然需要涉及管理&#xff0c;然而&#xff0c;如果仅仅将六西格玛法视为一种质量管理方法&#xff0c;必定会导致六西格玛管理法的失败。六西格玛法是一种具有特定战略性的管理方法&#xff0c;它涉及到市场、顾客、产品、服务、流程、质量、价值链以及财务…

Pytorch完整的模型训练套路

Pytorch完整的模型训练套路 文章目录 Pytorch完整的模型训练套路以CIFAR10为例实践 数据集加载步骤 使用适当的库加载数据集&#xff0c;例如torchvision、TensorFlow的tf.data等。 将数据集分为训练集和测试集&#xff0c;并进行必要的预处理&#xff0c;如归一化、数据增强等…

深搜回溯剪枝-全排列

LCR 083. 全排列 - 力扣&#xff08;LeetCode&#xff09; 根据题意&#xff0c;要根据给定的整数数组&#xff0c;穷举出所有可能的排列&#xff0c;从直观的角度上来看&#xff0c;可以使用多层 for 循环来解决&#xff0c;但如果是数组长度太大的时候&#xff0c;这种方式不…

配置Java环境变量不生效的解决办法

问题&#xff1a; 直接更换Java_HOME的JDK安装路径后&#xff0c;竟然环境变量不生效&#xff0c;在cmd窗口输入java -version或者javac -version后报错&#xff1f;&#xff1f;&#xff1f;这是为什么呢&#xff1f; 问题剖析&#xff1a; 在使用安装版本的JDK程序时&#…

DataFunSummit:2023年数据基础架构峰会-核心PPT资料下载

一、峰会简介 正如From、Join、排序等是SQL的基本算子&#xff0c;存储与计算是也是数据架构中数据生产与消费的基本算子&#xff0c;对于数据架构之下的技术栈层级&#xff0c;我们可将其定义为数据基础架构。 数据存储技术在适应大数据时代的规模需求基础之上&#xff0c;持…

【23真题】难!985难度前五名!

今天分享的是23年中山大学884的信号与系统试题及解析。 本套试卷难度分析&#xff1a;22年中山大学884考研真题&#xff0c;我也发布过&#xff0c;若有需要&#xff0c;戳这里自取!22年并不是很难&#xff0c;今年难度突然大幅度提升&#xff01;原因不明。23年平均分为100分…

新手教师如何迅速成长

对于许多新手教师来说&#xff0c;迈出教学的第一步可能会感到非常困难。不过&#xff0c;通过一些关键的策略和技巧&#xff0c;还是可以快速提升教学能力的&#xff0c;我将为大家提供一些实用的建议&#xff0c;帮助各位在教育领域迅速成长。 深入了解学科知识 作为一名老师…

数据库编程sqlite3库安装及使用

数据库编程 数据库的概念 数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。 数据库是存放数据的仓库。它的存储空间很大&#xff0c;可以存放百万条、千万条、上亿条数据。但是数据库并不是…

postgresql:记录表膨胀引起的io问题的处理

文章目录 1. io异常2.查看profile报告2.1 生成事发时间段的pgprofile2.2 查看报告 3.检查table是否膨胀4.执行vacuum full5.总结 1. io异常 iostat -x 1 20 Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq…

老师怎么才能让学生听话

在教育学生的过程中&#xff0c;如何让他们听话并且尊重师长&#xff0c;是一个老师需要深入思考的问题。这不仅涉及到学生的学习进步&#xff0c;还关系到他们的人格形成。以下是一些方法和策略&#xff0c;帮助教师更好地引导学生&#xff0c;使他们更愿意听从教导。 建立信任…

轻量封装WebGPU渲染系统示例<36>- 广告板(Billboard)(WGSL源码)

原理不再赘述&#xff0c;请见wgsl shader实现。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/BillboardEntityTest.ts 当前示例运行效果: WGSL顶点shader: group(0) binding(0) var<uniform> objMat :…

【机器学习】对比学习(contrastive learning)

对比学习是一种机器学习技术&#xff0c;算法学习区分相似和不相似的数据点。对比学习的目标是学习数据的表示&#xff0c;以捕捉不同数据点之间的基本结构和关系。 在对比学习中&#xff0c;算法被训练最大化相似数据点之间的相似度&#xff0c;并最小化不相似数据点之间的相似…

U-boot(三):start.S

本文主要探讨x210的uboot的start.S文件,也是uboot启动的第一阶段。 头文件 config.h config.h x210_sd.h,由mkconfig脚本生成,包含了开发板的配置宏 rootkaxi-virtual-machine:~/qt_x210v3s_160307/uboot/include# cat config.h /* Automatically generate…