DEV Community

Shubham Bhati
Shubham Bhati

Posted on

Preventing Cache Penetration in Spring Boot Using Redis and Bloom Filters

Preventing Cache Penetration in Spring Boot Using Redis and Bloom Filters

Cache penetration occurs when high-frequency requests query non-existent keys, bypassing the Redis cache completely and hitting the relational database directly.

Here is how we set up a Bloom Filter guard layer in front of Redis and PostgreSQL.


1. The Bloom Filter Guard Concept

A Bloom Filter is a space-efficient probabilistic data structure that tests whether an element is definitely NOT in a set or MIGHT be in a set.

@Component
public class CachePenetrationGuard {

    private final BloomFilter<String> accountFilter;

    public CachePenetrationGuard() {
        // Expected insertions: 500,000, False positive probability: 0.01 (1%)
        this.accountFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 500000, 0.01);
    }

    public void registerKey(String accountId) {
        accountFilter.put(accountId);
    }

    public boolean mightContain(String accountId) {
        return accountFilter.mightContain(accountId);
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Service Layer Verification

Before querying Redis or PostgreSQL, verify with the Bloom Filter:

@Service
public class AccountService {

    private final CachePenetrationGuard guard;
    private final RedisTemplate<String, AccountDto> redisTemplate;
    private final AccountRepository repository;

    public AccountDto getAccount(String accountId) {
        // Step 1: Bloom filter pre-check
        if (!guard.mightContain(accountId)) {
            return null; // Instant rejection, saves DB from unnecessary lookups
        }

        // Step 2: Redis lookup
        AccountDto cached = redisTemplate.opsForValue().get("acc:" + accountId);
        if (cached != null) return cached;

        // Step 3: DB fetch and cache populate
        AccountDto dbResult = repository.findByAccountId(accountId);
        if (dbResult != null) {
            redisTemplate.opsForValue().set("acc:" + accountId, dbResult, Duration.ofMinutes(30));
        }
        return dbResult;
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Summary

Combining Bloom Filters with TTL jitter in Redis shields backend databases from cache penetration and traffic spikes under production loads.

How do you protect your caching layers in Spring Boot? Let's discuss in the comments!

Top comments (0)