spring boot应用优化,6s内启动,内存减半

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: taptap-developer是一个spring boot框架驱动的纯Grpc服务,所以,只用了四步,移除了web和spring cloud相关的模块后,启动速度就稳稳的保持在了6s内。除了启动速度提升外,在服务待机状态下,内存锐减了50%左右,从500M左右的内存占用,缩减到了250M不到。

前言

taptap-developer是一个spring boot框架驱动的纯Grpc服务,所以,只用了四步,移除了web和spring cloud相关的模块后,启动速度就稳稳的保持在了6s内。除了启动速度提升外,在服务待机状态下,内存锐减了50%左右,从500M左右的内存占用,缩减到了250M不到。

分析日志

03901487-AE45-49C7-852C-81E4D4827BEF.png
日志是一个应用的门面,在未深入了解一个应用的架构前,通过启动的日志输出基本可以分析出这个应用的大概的技术构成。在分析日志之前,在强调一点,这个应用是一个纯Grpc的服务。如上图贴出的日志,是未优化前的系统日志输出,从上到下有四个红色箭头指向,是本次日志分析的关键信息,下面就这四个关键信息,分别分析下。然后总结出常见的优化方法

优化点一:关于Spring Data repository scanning

Spring Data repository是一个高度抽象的数据访问层接口,常见的实现有redis、jdbc、jpa、MongoDB、elasticsearch等等。实现一个Spring-data-xxx包,需要实现org.springframework.data.repository.core.support.RepositoryFactorySupport抽象类,然后在!/META-INF/spring.factories文件中定义好实现类。spring容器启动时,会扫描加载factories的信息。如果一个项目里有被扫描到有多个spring-data-xxx的实现,启动时日志就会打印Multiple Spring Data modules found, entering strict repository configuration mode!

优化:看到这个日志,我们就需要检查下项目中是否用到了这些功能,比如引入了spring-data-redis,其实只用到了其携带的jedis,而且jedis实例可能还是自己实例化的,这个时候就可以禁用repository的功能。参考配置如下:spring.data.redis.repositories.enabled=false

Spring Data repository有三种内置的初始化模式,分别对应如下:

  • DEFAULT:和Spring其他Bean一样,在容器上下文加载时就初始化
  • DEFERRED:惰性加载,容器上下文启动完成后开始初始化
  • LAZY:惰性加载,并且延迟注入,容器上下文启动完成接收第一个请求时开始初始化
    如日志输出:Bootstrapping Spring Data repositories in DEFAULT mode,默认是随容器启动就开始初始化的,

优化:这里可以根据业务特点,选择延迟加载,参考配置spring.data.jpa.repositories.bootstrap-mode=lazy

Spring Data repository会扫描项目中的实现了repository接口的类,默认情况下会盲扫所有的jar包,日志输出:Finished Spring Data repository scanning in 148ms. Found 0 repository interfaces.打印出了扫描repository接口的耗时情况。

优化:这里可以通过@EnableRedisRepositories(basePackages = "com.taptap")指定扫描的路径,可以显著提升扫描加载的速度

优化点二:关于WebApplicationContext

在spring中,WebApplicationContext是ApplicationContext的增强,由spring-web-mvc实现,增加了servlet、session等web相关的内容。从日志Initializing Spring embedded WebApplicationContext可以看出,我们初始化了一个web容器,而纯Grpc服务用不到Web的容器上下文,所以移除如下依赖即可

优化:移除implementation('org.springframework.boot:spring-boot-starter-web')

优化点三:关于servlet容器

spring-web-mvc是基于java web标准servlet设计架构的。而servlet是由servlet容器来驱动的,常见的servlet有tocmat、jetty、undertow等。从日志中可看出,我们启动了一个8081的servlet容器。这个不应该出现在纯Grpc的服务中,所以,直接移除即可。

优化:移除implementation 'org.springframework.boot:spring-boot-starter-undertow'

优化点四:关于archaius配置组件

从最后一个箭头指向的日志信息可以分析出,项目引入了archaius配置加载组件,所以项目在启动时,archaius会尝试去加载默认策略的配置源。而我们整体的技术栈,配置中心统一采用了apollo,所以可以直接移除,最后通过分析定位,archaius不是单独引入的,是随着spring-cloud-starter-netflix-hystrix一同引入,这个组件是spring-cloud-netflix微服务框架最常用的,但是在这边,目前所有的微服务都是直接注册到k8s容器的,所有服务的熔断、限流、负载均衡都下沉到了容器基数设施平台,所以应用层面虽然引入了这个包,其实没有实际作用,所以最后移除spring cloud相关组件

优化:移除implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'和 implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'组件、

附优化后的日志输出:
7C38C587-5CE2-4DAA-A79B-EDC2ADD43C7C.png

系统资源的变化

优化前的
A4E82AA8-74AA-4B0B-81EF-0C6AB2F5CBB7.png
优化后的
C8CB365E-6592-44A5-BC20-73472336D435.png
最后,基于资源监控图,从三个维度总结下,优化后的资源占用情况:

资源名称 优化前 优化后
内存 500M左右 250M左右
总线程数 107 78
装载类 12922 10041
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
3月前
|
Java 数据库连接 测试技术
SpringBoot入门 - 添加内存数据库H2
SpringBoot入门 - 添加内存数据库H2
129 3
SpringBoot入门 - 添加内存数据库H2
|
2月前
|
JSON Java API
利用Spring Cloud Gateway Predicate优化微服务路由策略
Spring Cloud Gateway 的路由配置中,`predicates`​(断言)用于定义哪些请求应该匹配特定的路由规则。 断言是Gateway在进行路由时,根据具体的请求信息如请求路径、请求方法、请求参数等进行匹配的规则。当一个请求的信息符合断言设置的条件时,Gateway就会将该请求路由到对应的服务上。
156 69
利用Spring Cloud Gateway Predicate优化微服务路由策略
|
11天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
106 17
Spring Boot 两种部署到服务器的方式
|
13天前
|
Java 应用服务中间件 API
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
31 5
|
2月前
|
运维 监控 Java
为何内存不够用?微服务改造启动多个Spring Boot的陷阱与解决方案
本文记录并复盘了生产环境中Spring Boot应用内存占用过高的问题及解决过程。系统上线初期运行正常,但随着业务量上升,多个Spring Boot应用共占用了64G内存中的大部分,导致应用假死。通过jps和jmap工具排查发现,原因是运维人员未设置JVM参数,导致默认配置下每个应用占用近12G内存。最终通过调整JVM参数、优化堆内存大小等措施解决了问题。建议在生产环境中合理设置JVM参数,避免资源浪费和性能问题。
100 3
|
3月前
|
JSON 安全 算法
Spring Boot 应用如何实现 JWT 认证?
Spring Boot 应用如何实现 JWT 认证?
100 8
|
3月前
|
消息中间件 Java Kafka
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
76 1
|
3月前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
79 13
|
3月前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
69 2
|
3月前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
70 4