Backend Development 9 min read

Redis Lazy Loading Cache with Guava Local Cache: Design, Implementation, and Evaluation

This article explains how to combine Redis lazy‑loading caching with Guava local cache in Java, presenting design diagrams, full code examples, and a discussion of the advantages, disadvantages, and suitable scenarios for this hybrid caching strategy.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Redis Lazy Loading Cache with Guava Local Cache: Design, Implementation, and Evaluation

In modern backend development, Redis is frequently used as a high‑performance cache to offload read traffic from relational databases, but heavy I/O can still become a bottleneck. Introducing a local cache such as Guava can reduce Redis read/write pressure while keeping the implementation simple.

Design Example – Redis Lazy Loading Cache

The proposed pattern stores data in MySQL without caching on creation; when a precise query occurs, the data is fetched from the database and then cached in Redis, achieving a "cache‑on‑read" behavior. A flow diagram illustrates the process.

// Pseudo‑code example – XxLazyCache
public class XxLazyCache {
    @Autowired
    private RedisTemplate
redisTemplate;
    @Autowired
    private XxService xxService;

    /**
     * Query: first check cache, then DB, finally populate cache.
     */
    public Xx getXx(int id) {
        Xx xxCache = getXxFromCache(id);
        if (xxCache != null) {
            return xxCache; // fast path
        }
        Xx xx = xxService.getXxById(id);
        setXxFromCache(xx);
        return xx;
    }

    /** Delete cache after update/delete */
    public void deleteXxFromCache(long id) {
        String key = "Xx:" + id;
        redisTemplate.delete(key);
    }

    private void setXxFromCache(Xx xx) {
        String key = "Xx:" + xx.getId();
        redisTemplate.opsForValue().set(key, xx);
    }

    private Xx getXxFromCache(int id) {
        String key = "Xx:" + id;
        return redisTemplate.opsForValue().get(key);
    }
}

// Service and entity classes omitted for brevity

The advantages of this approach are minimal cache size, low intrusion on CRUD operations, and plug‑in compatibility for legacy systems. The drawbacks include limited suitability for ever‑growing data sets and challenges in distributed micro‑service environments.

Redis Combined with Local Cache

In micro‑service scenarios where many services share a large Redis cache, a local Guava cache can further reduce latency and Redis load because it eliminates network round‑trips for hot keys.

Use case: assigning incremental IDs to devices in a high‑frequency streaming pipeline. The incremental counter is stored in Redis (using INCR ) and cached in a Redis hash; Guava caches the per‑device ID locally to avoid repeated hash lookups.

// DeviceIncCache – Guava + Redis hybrid cache
public class DeviceIncCache {
    /** Local Guava cache */
    private Cache
localCache = CacheBuilder.newBuilder()
        .concurrencyLevel(16)
        .initialCapacity(1000)
        .maximumSize(10000)
        .expireAfterAccess(1, TimeUnit.HOURS)
        .build();

    @Autowired
    private RedisTemplate
redisTemplate;

    private static final String DEVICE_INC_COUNT = "device_inc_count"; // Redis INCR key
    private static final String DEVICE_INC_VALUE = "device_inc_value"; // Redis hash key

    /** Get or generate incremental ID for a device */
    public int getInc(String deviceCode) {
        Integer inc = localCache.getIfPresent(deviceCode);
        if (inc != null) {
            return inc;
        }
        inc = (Integer) redisTemplate.opsForHash().get(DEVICE_INC_VALUE, deviceCode);
        if (inc == null) {
            inc = redisTemplate.opsForValue().increment(DEVICE_INC_COUNT).intValue();
            redisTemplate.opsForHash().put(DEVICE_INC_VALUE, deviceCode, inc);
        }
        localCache.put(deviceCode, inc);
        return inc;
    }
}

Advantages of this hybrid approach include persistent Redis data, ultra‑fast reads from Guava, controllable memory usage via expiration policies, and suitability for distributed deployments where each instance caches only its own subset of keys. Disadvantages are added implementation complexity and the fact that it only fits scenarios where cached data is append‑only (no updates).

Overall Summary

Local cache size is controllable and eviction policies are robust.

Ideal for precise‑query use cases and micro‑service architectures.

Not suitable when cached data changes frequently or when the total data volume is unbounded.

Provides significant performance gains by reducing Redis I/O.

By leveraging Redis’s rich data structures together with Guava’s flexible caching API, developers can achieve a balanced trade‑off between memory consumption and response latency in backend systems.

BackendJavaRediscachingGuavalocal cacheLazy Loading
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.