🚀 Spring Boot Performance Tuning: From 1k to 100k Requests Per Second
A practical guide to scaling Spring Boot applications using JVM tuning, connection pooling, caching, and architecture improvements.
Introduction
Spring Boot is one of the most widely used frameworks for building Java microservices. It allows developers to create REST APIs quickly and deploy them easily.
However, many Spring Boot applications struggle when traffic increases.
An API that handles 1,000 requests per second might suddenly fail when the load reaches 10,000 requests per second.
The reason is usually poor performance tuning.
Performance tuning is not about writing faster code. It is about removing system bottlenecks.
In this article, we will walk through practical steps to improve Spring Boot performance and scale applications from 1k to 100k requests per second.
Why Spring Boot Performance Matters
Modern applications often serve thousands of users simultaneously.
Poor performance can cause:
- High API latency
- Slow database responses
- Memory pressure
- Application crashes
When performance problems appear in production, they can lead to:
503 Service Unavailable
504 Gateway Timeout
OutOfMemoryErrorA well-tuned system ensures:
- Faster response times
- Lower infrastructure costs
- Better user experience
Understanding the Performance Bottlenecks
Before optimizing performance, it’s important to identify where bottlenecks occur.
Most Spring Boot applications slow down because of these components:
Client
↓
Load Balancer
↓
Spring Boot API
↓
Database / External ServicesCommon bottlenecks include:
- JVM configuration
- Database queries
- Thread management
- External API calls
- Memory usage
- Serialization overhead
Each of these must be optimized.
Step 1: Optimize JVM Configuration
The Java Virtual Machine controls memory allocation and garbage collection.
Incorrect JVM configuration can dramatically reduce performance.
A basic optimized configuration might look like this:
java -Xms2g -Xmx2g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-jar application.jarExplanation:
Setting equal Xms and Xmx prevents unnecessary heap resizing.
Step 2: Use Connection Pooling Correctly
Every database request requires a connection.
Creating a connection for each request is extremely expensive.
Spring Boot uses HikariCP as the default connection pool.
Example configuration:
spring:
datasource:
hikari:
maximum-pool-size: 30
minimum-idle: 10
idle-timeout: 600000
connection-timeout: 30000Important rule:
Maximum pool size ≈ (CPU cores × 2) + disk latency factorToo many connections can overload the database.
Step 3: Database Query Optimization
Database performance often determines the overall system performance.
Avoid inefficient queries like this:
for(Long userId : userIds){
User user = userRepository.findById(userId);
}This creates multiple database calls.
Instead, use batch queries.
List<User> users = userRepository.findAllById(userIds);Additional optimizations:
- Add database indexes
- Avoid unnecessary joins
- Use pagination for large datasets
Example pagination:
Page<User> users = userRepository.findAll(PageRequest.of(0, 20));Step 4: Enable Caching
Caching reduces repeated database queries.
Get Dolly’s stories in your inbox
Join Medium for free to get updates from this writer.
Spring Boot provides simple caching support.
Example:
@Cacheable("users")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
Configuration:
spring:
cache:
type: caffeineBenefits:
- Faster responses
- Reduced database load
- Improved scalability
Step 5: Use Asynchronous Processing
Long-running tasks should not block API threads.
Example synchronous processing:
public void processOrder(Order order) {
paymentService.process(order);
emailService.sendConfirmation(order);
}Better approach using asynchronous execution:
@Async
public void sendConfirmationEmail(Order order){
emailService.sendConfirmation(order);
}Enable async support:
@EnableAsync
@SpringBootApplication
public class Application {
}Now the API response returns immediately.
Step 6: API Response Optimization
Large responses slow down APIs.
Bad example:
@GetMapping("/users")
public List<User> getUsers(){
return userRepository.findAll();
}Better approach:
@GetMapping("/users")
public Page<User> getUsers(Pageable pageable){
return userRepository.findAll(pageable);
}Another improvement is using DTOs.
Example:
public class UserDTO {
private Long id;
private String name;
}DTOs reduce payload size.
Step 7: Load Testing Your Application
Performance tuning is impossible without load testing.
Popular tools include:
- JMeter
- Gatling
- k6
Example k6 load test script:
import http from "k6/http";
import { sleep } from "k6";
export default function () {
http.get("http://localhost:8080/api/users");
sleep(1);
}Run the test:
k6 run test.jsLoad testing reveals:
- Latency
- Error rate
- Throughput
Production Architecture for 100k RPS
To handle massive traffic, the architecture must scale horizontally.
Example architecture:
Users
↓
CDN
↓
Load Balancer
↓
API Gateway
↓
Spring Boot Microservices
↓
Redis Cache
↓
Database ClusterKey improvements:
- API Gateway for routing
- Redis caching
- Database replication
- Horizontal scaling
This architecture supports extremely high throughput.
Final Thoughts
Spring Boot can handle massive workloads when properly tuned.
Scaling from 1k to 100k requests per second requires improvements in multiple layers:
- JVM configuration
- Database performance
- Connection pooling
- Caching
- Asynchronous processing
- API response optimization
- Load testing
Performance is not achieved by one change, but by improving every layer of the system.
With proper monitoring and tuning, Spring Boot applications can scale to handle very high traffic loads.











