10 Spring Boot Performance Best Practices
Spring Framework?is one of the most popular and mature application development frameworks available in the Java ecosystem, and?Spring Boot?simplifies the process of creating Spring-powered applications by providing pre-configured modules, automatic configuration, starter dependencies, and more. This simplicity, popularity, and maturity have caused many systems out there to be implemented with Spring Boot, and it is quite possible that?some of them are not optimized and performant.
In this article, we will first discuss what performance is in general, and then we will discuss 10 Spring Boot Performance Best Practices to make our Spring Boot fast and resource-efficient.
Table of Contents
What do we mean when we say performance?
Traditionally, Performance refers to how effectively an application performs its tasks (Runtime efficiency), which we also call?speed, and how efficiently it uses system resources (Resource efficiency).
In modern software development, Performance has different aspects that are somehow related to these two (Runtime & Resource efficiency):
Typically, the performance of a software application is all about making sure it runs smoothly, quickly, and effectively. It also involves managing resources efficiently and meeting the expectations of users.
How to improve Spring Boot performance?
In the coming sections, we will address ten best practices that will help us to have a performant Spring Boot application. These are not listed in any particular order, and some of them might be applicable to the newer version of Spring Boot.
1 - Using the latest version of Spring Boot as much as possible
In every version of Spring Framework and Spring Boot, besides introducing new features and functionalities, there are also several improvements in performance by optimizing the Spring core container and modules, fixing bugs, and more. So, it is highly recommended that you use as many of the latest versions of Spring Boot as possible.
2 - JVM version and tuning
Similar to Spring Boot, every?Java LTS release?has a lot of performance improvements. Sometimes, to leverage the performance improvements in the latest version of Spring Boot, we need to use the latest version of Java.
Although the latest version of JVM will improve the performance of your Spring Boot application, JVM tuning can further improve the performance of our Spring Boot application. JVM tuning is out of the scope of this article, but I can mention some areas that we need to pay attention to:
Optimal JVM and GC settings differ based on your application and environment. Testing various configurations and monitoring performance are essential to identify the best settings.
3 - Using Virtual Threads in Web MVC stack on JDK 21
Since version 3.2, Spring Boot has started to support Virtual Threads (Project Loom) in different ways. You can find more information about it in my previous article about this feature: Read more: Here
To use this feature, you need to use JDK 21 or higher,
The most important advantage of Virtual Threads is that they improve the?Scalability?and?Performance?of Spring Boot applications by introducing a lightweight threading model while keeping?backward compatibility?and?decreasing the complexity?of asynchronous programming without sacrificing performance.
We can easily enable Virtual Threads in Spring Boot using this config:
spring.threads.virtual.enabled=true
By existing in this config, Spring Boot Web MVC is handling a web request, such as a method in a controller, which will run on a virtual thread.
4 - Spring AOT and Spring GraalVM Native Image
GraalVM Native Images offers a new approach to running Java applications with?reduced memory usage?and significantly?faster startup times?compared to the JVM
It is ideal for container-based deployments and Function-as-a-Service platforms, GraalVM Native Images require ahead-of-time processing to create an executable through static code analysis. The result is a platform-specific, standalone executable that doesn’t need a JVM for runtime.
Since GraalVM is not directly aware of dynamic elements of our Java code, such as?reflection,?resources,?serialization, and?dynamic proxies, we need to provide some information about those elements for GraalVM. On the other hand, Spring Boot applications are dynamic, with configuration performed at runtime.
Spring AOT?(Ahead-of-Time) processing is a feature provided by the Spring Framework that enables the transformation of Spring applications to make them more compatible with GraalVM.
Spring AOT performs ahead-of-time processing during?build time?and generates additional assets such as Java codes, bytecodes, and GraalVM JSON hint files that help GraalVM for ahead-of-time compilation.
[image for ahead-of-the-time processing and ahead-of-the-time compilation]
To achieve this, we need to use the GraalVM build tools plugin in our Spring Boot project:
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
Then, to build the GraalVM Native Image, we can run the?spring-boot:build-image?goal with the?native?profile active:
mvn -Pnative spring-boot:build-image
It will create a docker image using Buildpacks for us. If you want to know more about the Cloud Native Buildpacks and how Spring Boot is using it, read this article.
To generate a?native executable?instead of a Docker image, we can run this command (make sure that a GraalVM distribution is installed on your machine):
mvn -Pnative native:compile
5 - JVM Checkpoint Restore feature (Project CRaC)
This feature was added to Spring Boot from version?3.2?and provided by the JVM to enable a running Java application to?save its state, called a “checkpoint,” and then?restore that state?at a later time. Spring Boot integrated this feature with its?ApplicationContext?lifecycle for the automatic checkpoint, and it can be used simply by adding the –Dspring.context.checkpoint=onRefresh?parameter.
This feature can improve the performance of a Spring Boot application in the following ways:
To use this feature, we need to install a?CRaC-enabled?version of the JDK and use Spring Boot 3.2 or later.
领英推荐
To know more about this feature, you can read our previous deep article about this feature: read more: Here
6 - Class Data Sharing (CDS)
Class Data Sharing (CDS) is a feature of the Java Virtual Machine (JVM) that can help decrease Java applications’?startup time?and?memory footprint. Starting in version 3.3, it was integrated into Spring Boot.
The CDS feature comprises two main steps:?1—Creating the CDS Archive, which creates an archive file (with?.jsa?format) containing the application classes when the application exits?2—Using the CDS Archive, which loads the?.jsa?file into memory.
CDS reduces the Spring Boot application startup time because accessing the shared archive is faster than loading the classes when the JVM starts. It is also a memory-efficient solution because:
A portion of the shared archive on the same host is mapped as read-only and shared among multiple JVM processes, and also the shared archive contains class data in the form that the Java Hotspot VM uses it.
7 - Configuring threads for Spring MVC and Database centric app
Spring Boot application can handle multiple requests in parallel, and the key factor to achieve high throughput is to have enough thread to handle requests. Two important layers that can cause bottlenecks and need to be configured carefully are the Controller and Database access layers.
???Controller layer threads configuration:
If you cannot use the Virtual Thread feature in your Spring MVC application for any reason, it is very important to properly configure the?thread pool?for the controller layer.
Since Spring MVC applications run on?servlet containers?like Tomcat, Jetty, or Undertow, we need to know specific configuration keys for our servlet containers to configure the thread pool. For example, in the case of Tomcat, we have two important keys for thread configuration:
server:
tomcat:
connection-timeout: 2s
keep-alive-timeout: 10s
threads:
max: 500
min-spare: 100
Depending on the servlet container you are using, there are more configurations that can help us configure it for better performance. For example, for Tomcat, there are two timeout-related configs (server.tomcat.connection-timeout and server.tomcat.keep-alive-timeout) that might need to be adjusted to improve performance.
??? Database access layer threads configuration:
Since JDBC is a connection-oriented standard for communicating with a database, it is very important to use a?connection pool. By default, Spring Boot uses?HikariCP?as the connection pool. Similar to servlet containers, each connection pool library has its own configuration key to configure it, for HikariCP the most important config for the connection pool are:
spring:
datasource:
username: deli
password: p@ssword
url: jdbc:postgresql://localhost:5432/sample_db
hikari:
maximum-pool-size: 400
minimum-idle: 100
connection-timeout: 2000
8 - Use caching strategies
Choosing a proper caching strategy for our Spring Boot application can greatly improve its performance. These days, we have many microservices with data spread between them. By leveraging a proper caching strategy, we can improve performance and cut several round trips.
Based on the application’s scale, data access patterns, and performance requirements, we need to decide about two important aspects of caching:
1 - What do we cache??What piece of information in our application do we want to keep in the cache?
2 - How do we cache??What mechanism or approach of caching do we use? Do we want to use local cache, distributed cache, or both? For how long do we want to keep a piece of data in the cache?
Fortunately, Spring Boot provides a set of useful libraries to help us with caching. We have a dedicated article about caching strategies in Spring Boot. You can read it: Here.
9 - Adopting resiliency patterns and best practices
I believe that this is a very important topic, especially these days, because of the increasing number of applications based on the microservices architecture.
Following resiliency patterns such as?Circuit Breaker,?Timeouts, Fallback, and Retries?helps Spring Boot applications better handle failures, allocate resources efficiently, and provide consistent performance, ultimately leading to an improved overall application performance.
Spring Boot supports resiliency patterns through several built-in features and integrations with popular libraries like?Resilience4j. Spring Boot simplifies the integration of Resilience4j by?auto-configuring?the required beans and providing a convenient way to configure resilience patterns through properties or?annotations.
Spring Cloud Circuit Breaker?provides an abstraction layer for circuit breakers, and Resilience4j can be configured to be used under the hood.
@Service
public static class DemoControllerService {
private RestTemplate rest;
private CircuitBreakerFactory cbFactory;
public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory){
this.rest = rest;
this.cbFactory = cbFactory;
}
public String slow() {
return cbFactory.create("slow").run(
() -> rest.getForObject("/slow", String.class), throwable -> "fallback"
);
}
}
10 - Monitoring and Profiling
By combining monitoring and profiling, you can gain a deep understanding of your Spring Boot application’s performance and make data-driven decisions to improve it. In our last article, we went deep into Static and Dynamic code analysis and its relation with finding performance problems using Monitoring and Profiling: Read more: Here.
Spring Boot, out of the Box, has many libraries and tools for this purpose.?Spring Boot Actuator?can monitor application health, gather metrics, and identify performance bottlenecks. On the other hand, from Spring Boot 3.x, there is very good integration with?Micrometer?using Spring autoconfiguration, which helps us have better metrics and distributed tracing, which, lastly, leads to better application monitoring.
Final Thought: 10 Spring Boot Performance Best Practices
In this article, we reviewed ten ways to improve Spring Boot application performance. Some improve?runtime performance, and some optimize the application’s?consumed resources. However, some approaches require using a specific Java and Spring Boot version. Of course, there are other ways to improve Spring programs, especially best practices that can apply at the coding level. I would be happy if you mentioned other best practices in the comment section.
? Top Computer Science Voice | CS Undergraduate Student @ HCMUT
2 个月Thanks for sharing !
??Top Back-end Development, Databases Voice | Software Engineer
3 个月Love this
Insightful!
Database Developer | Database Administrator | Database Oracle #performanceturning, and #toiuucosodulieu
3 个月thank for sharing
Step by step, you will get there one day!
3 个月Thanks for sharing??