DISTRIBUTED SYSTEMS & CACHING#08 • Performance & Scalability

Caching in Spring Boot: In-Memory vs. Redis Distributed Cache.

Spring Boot provides built-in in-memory caching out of the box, but as soon as you scale horizontally, local JVM caches break down. Learn why Redis is essential for production microservices, how Spring Cache abstractions work, and how to transition seamlessly from local memory to distributed caching.

By Shyam KumarMay 16, 20268 min read
#SpringBoot#Redis#Caching#DistributedSystems
01 / CORE PRINCIPLES

What is Caching and Why Does It Matter?

Caching means storing frequently accessed data in fast, temporary storage (RAM) so future requests can be served without querying slow relational databases or calling external third-party APIs.

⚡ Reducing DB Load

Offloads 80-95% of repeated read queries from PostgreSQL or MySQL, saving disk I/O and connection pools.

⏱️ Improving Latency

RAM lookups return data in sub-milliseconds (e.g., 0.5ms) compared to 50–200ms database disk queries.

📈 Better Scalability

Enables your backend to effortlessly handle flash sales, sudden traffic surges, and high concurrent user loads.

“Spring Boot already provides caching out of the box... but Redis takes caching to the next level.”

However, not all caches work the same way. Spring Boot supports two primary categories: In-Memory Cache and Distributed Cache. Understanding their fundamental trade-offs is essential before going to production.
02 / DEFAULT SPRING CACHE

In-Memory Caching (How It Works)

Spring Boot provides in-memory caching by default when you add the @EnableCaching annotation.

Characteristics of In-Memory Cache:

  • •Stored in JVM Heap Memory: The cached entries live directly inside the Java Virtual Machine process heap.
  • •Default Implementation: Internally uses a thread-safe ConcurrentHashMap (or Caffeine/Ehcache if configured).
  • •Zero Configuration: Simple and blazingly fast to set up for local development.

Spring Cache Annotations Suite:

@Cacheable
Checks cache first; executes method only on cache miss
@CachePut
Always executes method and updates cache with return value
@CacheEvict
Removes stale entries on update/delete operations
@Caching / @CacheConfig
Groups multiple caching rules or sets class-level cache names
UserService.java(Java / Spring Boot)
// Spring Boot Caching Annotations
package com.example.demo.service;

import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepo;

    public UserService(UserRepository userRepo) {
        this.userRepo = userRepo;
    }

    // 1. @Cacheable: If key exists in cache, return it. Otherwise execute DB query and cache result.
    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        System.out.println("Fetching from Database for ID: " + id);
        return userRepo.findById(id).orElseThrow();
    }

    // 2. @CachePut: Always executes method and updates cache with fresh data
    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        return userRepo.save(user);
    }

    // 3. @CacheEvict: Removes entry from cache on deletion to prevent stale reads
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        userRepo.deleteById(id);
    }
}
03 / ARCHITECTURAL BOTTLENECK

The Fatal Flaw with In-Memory Caching

In-memory caching works fine for a monolithic, single-instance app on a developer's laptop. However, modern production environments deploy applications across multiple container instances (Kubernetes pods, AWS ECS, or autoscaling EC2 groups).

❌ THE MULTI-NODE CACHE INCONSISTENCY TRAP:
            [Load Balancer / Nginx]
                 │                 │
                 ▼                 ▼
   ┌──────────────────────┐       ┌──────────────────────┐
   │   Spring Boot Pod 1   │       │   Spring Boot Pod 2   │
   │  [Local JVM Cache]   │       │  [Local JVM Cache]   │
   │  user:101 'Shyam'    │       │  user:101 'OLD_NAME' │ ← STALE DATA!
   └──────────────────────┘       └──────────────────────┘
User updates name via Pod 1. Pod 1 evicts its local cache. But Pod 2 never received the event and continues serving old data!
Not Shared Across Instances: Each node maintains its own isolated heap cache.
Lost on App Restart: Every CI/CD deployment or pod restart wipes out the entire cache, causing thundering herd DB spikes.
Heavy JVM Memory Pressure: Excessive caching in the heap triggers aggressive Java Garbage Collection (Stop-The-World GC pauses).
04 / DISTRIBUTED ARCHITECTURE

Redis: The Distributed In-Memory Solution

Redis (Remote Dictionary Server) is an open-source, in-memory NoSQL data store that operates as an external, centralized caching tier shared by all microservice instances.

✅ THE REDIS DISTRIBUTED CACHING TOPOLOGY:
   [Pod 1]           [Pod 2]           [Pod 3]           [Pod N]
     │                 │                 │                 │
     └─────────┬───────┴────────┬────────┴────────┬────────┘
               ▼                ▼                ▼
           ┌─────────────────────────────────────────┐
           │       CENTRALIZED REDIS CLUSTER         │
           │    (Shared, High-Availability RAM)      │
           └────────────────────┬────────────────────┘
                                │ (Only on Cache Miss)
                                ▼
           ┌─────────────────────────────────────────┐
           │       Primary SQL Database (Disk)       │
           └─────────────────────────────────────────┘

Why Redis is Production-Ready:

Centralized Shared State: All instances read and invalidate the exact same key-value store in real-time.
Persistence for Backup: RDB (point-in-time snapshots) and AOF (append-only file logging) protect cache data against server reboots.
Rich Native Data Structures: Not just Strings, but Hashes, Lists, Sets, Sorted Sets (ZSET), and HyperLogLog.
Built-in TTL & Eviction: Configurable Time-To-Live (TTL) and LRU (Least Recently Used) memory limits prevent Out-Of-Memory errors.
05 / ZERO CODE REWRITE

The Magic: You Just Plug Redis Underneath

Here is the best part of Spring's architectural design: All Spring Cache annotations (@Cacheable, @CacheEvict) remain 100% identical!

“Spring gives you the clean abstraction. Redis gives you the distributed power.”

You do NOT need to rewrite your business services with redisTemplate.opsForValue() calls. You simply add the Redis dependency, configure the host in YAML, and Spring Boot automatically binds its cache manager to Redis.
application.yml(YAML)
# application.yml
# Switching from default in-memory cache to distributed Redis
spring:
  cache:
    type: redis
    redis:
      time-to-live: 600000 # 10 minutes TTL
      cache-null-values: false
  data:
    redis:
      host: ${REDIS_HOST:localhost}
      port: 6379
      timeout: 2000ms
      lettuce:
        pool:
          max-active: 16
          max-idle: 8
          min-idle: 2
06 / DECISION MATRIX

In-Memory vs. Redis Comparison

CriteriaDefault In-Memory CacheRedis Distributed Cache
Storage LocationApplication JVM Heap MemoryExternal Centralized RAM Node
Multiple InstancesNot Shared (Separate cache per node)Shared across all nodes & services
Horizontal ScalingFails (Causes data inconsistencies)Seamless horizontal scaling
App Restart SurvivalCache is completely wiped outSurvives deployments & restarts
Infrastructure CostZero extra infra neededRequires managing Redis instance/cluster
Best ForSmall apps, monolithic, single podMicroservices, Kubernetes, High-Traffic
07 / SUMMARY

Final Takeaway: Scale Safely

Spring Boot caching is great to start with. Redis is what you need to scale safely:

✓In-Memory Cache: Ideal for simple, single-instance applications and rapid prototypes.
✓Redis: Mandatory for distributed, multi-node, production-grade microservice systems.

Did you find this distributed caching breakdown useful?

Help other backend engineers build resilient systems — please like and share with your team!

Like: If you learned something new
Share: Forward to your engineering peers
Back to All Articles in The Tech Corner
Discuss Architecture? Contact Me