你好呀,我是雨夜。
现在a项目 启动需要140s,2分钟以上了,需要优化
确定原因
使用 Spring Startup Analyzer
可视化 启动时间的分布,发现 @Bean的 初始化占用了 大部分时间
启动耗时分布
- @Bean的 扫描放到 ioc中 ,平均MapperFactoryBean 经过 classLoader 一个bean 要200ms左右
- @Bean的init方法(比如rpc调用其他项目接口,接口返回慢)
- 扫描 多余jar
怎么节省启动时间
针对耗时,有2个办法
- 减少@Bean 需要扫描的Class
- 减少@Bean 扫描放到ioc的耗时
- @Bean 的init 异步化
- 降低 rpc等自身调用耗时,优化代码和接口性能
- 去掉多余的jar
- springboot3 native化,省去了 JVM 加载和字节码运行期预热的时间
针对上面提出的办法 进行调研
减少@Bean 需要扫描的Class
平时写组件的时候 要把需要扫描的bean 通过spring.factories 进行准确指定,现在的问题是通过@SpringBootApplication 的scanBasePackages 进行大范围的扫描,导致扫描了无用的bean,同时要在写业务项目的时候,要在公司 公共的包名后面 添加 业务专属的标识,这样能防止 扫描无用的bean
减少@Bean 扫描放到ioc的耗时
2 org.mybatis.spring.mapper.MapperFactoryBean 生成一个 mapper的代理需要200ms左右,首先需要确定这200ms 都花费在哪,我用的是 arthas
MapperFactoryBean主要分为
- 获取 sqlSession
- return mapperProxyFactory.newInstance(sqlSession); 生成mapper代理,放到 spring ioc中
但是这里遇到一个问题,arthas 只能trace 一层,不能递归输出下层的细节耗时
@Bean 的init 异步化
这个能提升点性能,目前主要有2种
- SOFABoot
- spring6.2
SOFABoot 原理
SOFABoot 缺点:
- 必须手动指定异步化的Bean,其实手动指定,就已经输了,毕竟难度和体验感都差很多
最近从why哥 那看到spring6.2 已经开发了异步bean,本来以为spring 官方应该就不用手动指定异步化的Bean了,结果编译spring6.2 然后测试了一下,还是需要指定异步的bean
这个能提升启动速度,但是不是重点,先放放
降低 rpc等自身调用耗时,优化代码和接口性能
这个就是根据耗时比较长的,看是哪部分的问题,然后优化性能,如果使用异步,需要防止没加载完成,就被调用的问题
去掉多余的jar
有的jars 没有被使用,而加载了,可能是后面开发的时候 引入的,然后对功能没影响,就没有删除多余的
可以从 Spring Startup Analyzer 中 Unused Jars After Startup 展示了,可以针对性删除
springboot3 native化,省去了 JVM 加载和字节码运行期预热的时间
它是省去了 JVM 加载和字节码运行期预热的时间, 属于把时间花费在 代码编译阶段,后面启动 秒级
而且这是springboot 未来趋势
需要写一个springboot3 高性能基础骨架
过段时间 会发布一个 开源版本,大家可以关注本账号,也可以关注 yuyezhiji (yuyezhiji) (github.com)
本文章没写完,我会在6月10日之前补完