Scaling Spring Boot : Real-World Lessons

Jahid Momin
3 min readNov 18, 2024

--

Scaling Springboot Service

Hey dev’s ! 👋 After spending three years building and maintaining Spring Boot monolithic services that handle significant traffic, I wanted to share some practical lessons I’ve learned. These aren’t just theoretical concepts — they’re battle-tested solutions that have helped our services perform reliably in production.

Why I’m Writing This

When I first started working with Spring Boot, I struggled to find practical advice about handling high traffic. Most articles were either too theoretical or jumped straight into reactive programming and microservices. But here’s the thing — a well-configured monolithic Spring Boot application can handle substantial load just fine ! Let me share what’s worked for me.

1. Server Configuration : The Foundation

The first production issue I encountered was our application throwing timeout errors under load testing . Here’s what configuration fixed it :

server.tomcat.max-threads=500
server.tomcat.max-connections=10000
server.connection-timeout=120000

Pro tip : update configuration based on your requirements & load .

2. Database : The Most Common Bottleneck

In my experience, database issues cause 80% of performance problems. Here’s what I’ve learned:

Connection Pool Settings

# HikariCP settings
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=250
spring.datasource.hikari.idle-timeout=20000
spring.datasource.hikari.pool-name=MyApp-Datasource
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=20000

Pro tip: I learned the hard way that bigger pool sizes aren’t always better. Start small and increase only if needed.

One more thing important thing is to optimized queries .

The Magic of Proper Indexing

-- example
-- Before
SELECT * FROM orders WHERE user_id = ? AND status = 'ACTIVE' ORDER BY created_at DESC;

-- After adding this index, same query takes 100ms
CREATE INDEX idx_order_lookup ON orders(user_id, status, created_at);

3. Caching: Your Best Friend

you can use Spring’s default cache or third party caching such as redis

@Cacheable(value = "products", key = "#id")
public Product getProduct(Long id) {
return productRepository.findById(id).orElse(null);
}

But see if you want to plan to scalabality then go for redis

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=2000

Quick tip: Cache invalidation is tricky. I prefer short TTLs over complex invalidation logic.

4. Large Data Processing

One of our endpoints was timing out when handling longer processing requests . Spring batch processing approach will solved that issue like bulk operations.

5. JVM Settings That Actually Matter

To make your Java or Spring Boot application faster, follow JVM tuning tips. First, optimize heap memory by setting initial and maximum sizes to avoid runtime resizing issues. Use the G1 Garbage Collector for low-latency performance and enable garbage collection logs for debugging. Tools like GraalVM can improve startup time with AOT compilation, while Class Data Sharing reduces overhead during class loading. For containerized environments, adjust container-specific settings to effectively utilize resources. Lastly, continuous monitoring with profiling tools ensures optimal performance.

# Heap Memory Optimization
-Xms512m -Xmx1024m

# Use G1 Garbage Collector
-XX:+UseG1GC

# Enable Garbage Collection Logs
-Xlog:gc*,gc+cpu,gc+heap=info

# Ahead-of-Time Compilation (GraalVM)
native-image -jar app.jar

# Container-Specific Settings
-XX:+UseContainerSupport
-XX:MaxRAMPercentage=75

# Disable Biased Locking (For multi-threaded apps)
-XX:-UseBiasedLocking

# Enable Class Data Sharing
-Xshare:on

# Thread Pool Optimization
-XX:ParallelGCThreads=4 -XX:ConcGCThreads=2

6. REST API Design Lessons

The biggest lesson? Keep endpoints focused. Here’s example :

// Before: One endpoint doing too much
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
// 200 lines of business logic, email sending, inventory updates...
}

// After: Focused endpoints
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
Order order = orderService.createOrder(request); // Core logic only
eventPublisher.publishEvent(new OrderCreatedEvent(order)); // Let others handle side effects
return order;
}

Quick tip: Don’t forget to add Spring Actuator in you service to monitor metrics

You don’t need fancy architectures or reactive programming to handle high traffic. A well-configured Spring Boot monolith can take you far. Start with these basics, measure everything, and optimize based on real data.

Remember:

  • Monitor before optimizing
  • Keep it simple
  • Test with production-like data
  • Small, incremental improvements > big rewrites

Hope this helps with your scaling !

Follow for more , Thanks !

--

--

Jahid Momin
Jahid Momin

Written by Jahid Momin

Team Lead | Sr Software Engineer | Spring boot | Microservices | JavaScript | CodeIgniter | HTML | CSS | ReactJS | NextJS | Youtuber | Writer

No responses yet