Beyond Caching: 10 Advanced Redis Use Cases You’re Probably Missing

This article walks through ten advanced Redis features—including Bloom filters, Redisson distributed locks, delayed queues, token‑bucket rate limiting, bitmaps, HyperLogLog, GEO, Streams, Lua scripts, and RedisJSON—explaining their principles, pros and cons, typical scenarios, and providing complete Spring Boot code examples.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Beyond Caching: 10 Advanced Redis Use Cases You’re Probably Missing

Introduction

Redis provides advanced capabilities beyond caching, improving performance, scalability, and reliability.

Practical Cases

Bloom Filter

Used to prevent cache penetration in high‑concurrency systems.

Characteristics

~100 MB memory for 100 million entries.

Probabilistic false‑positive; "not exists" is always correct.

No native delete; use a counting Bloom filter when deletions are required.

Working principle

If any bit is 0, the element definitely does not exist.

If all bits are 1, the element probably exists (with a small false‑positive rate).

Spring Boot implementation (Redisson)

@Component
public class BloomFilterService {
    private final RedissonClient redissonClient;
    private final UserService userService;
    private RBloomFilter<String> bloomFilter;

    public BloomFilterService(RedissonClient redissonClient, UserService userService) {
        this.redissonClient = redissonClient;
        this.userService = userService;
    }

    @PostConstruct
    public void init() {
        bloomFilter = redissonClient.getBloomFilter("user:bf");
        bloomFilter.tryInit(1_000_000L, 0.01);
    }

    public void addUser(Long userId) {
        bloomFilter.add(userId.toString());
    }

    public User getUserById(Long userId) {
        if (!bloomFilter.contains(userId.toString())) {
            return null;
        }
        return userService.findById(userId);
    }
}

Pros Minimal memory usage; blocks cache‑penetration. Cons False positives; no native delete. Applicable scenarios Block malicious requests, filter spam, deduplicate crawler URLs. Distributed Lock Simple SET NX EX has pitfalls: improper TTL, unlocking without ownership verification, and lack of automatic renewal. Redisson implementation Redisson uses Lua scripts for atomic lock/unlock and a watchdog to extend TTL automatically. <code>@Service public class OrderService { private final RedissonClient redissonClient; public OrderService(RedissonClient redissonClient) { this.redissonClient = redissonClient; } public void processOrder(String orderId) { RLock lock = redissonClient.getLock("order:lock:" + orderId); try { if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { doProcess(orderId); } else { throw new RuntimeException("Failed to acquire lock"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Interrupted", e); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } </code> Pros Automatic renewal, re‑entrant, supports read/write locks and RedLock. Cons Requires Redisson dependency. Applicable scenarios Distributed task scheduling, inventory deduction, order creation. Redisson Delayed Queue Provides precise timed execution without polling, e.g., auto‑cancelling unpaid orders after 30 minutes. Principle Items with timestamps are stored in a sorted set; when the timestamp expires the item moves to a blocking queue for consumption. <code>@Component public class DelayQueueService { private final RedissonClient redissonClient; private final RBlockingQueue&lt;Order&gt; blockingQueue; private final RDelayedQueue&lt;Order&gt; delayedQueue; public DelayQueueService(RedissonClient redissonClient) { this.redissonClient = redissonClient; this.blockingQueue = redissonClient.getBlockingQueue("order:queue"); this.delayedQueue = redissonClient.getDelayedQueue(blockingQueue); } public void addOrder(Order order, long delay, TimeUnit unit) { delayedQueue.offer(order, delay, unit); } @Async public void startConsumer() { while (true) { try { Order order = blockingQueue.take(); processExpiredOrder(order); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } } </code> Pros High timing precision, distributed, data persisted automatically. Cons Tight coupling to Redis; retry and compensation logic must be implemented by developers. Applicable scenarios Order auto‑cancellation, delayed notifications, timed task distribution. Token‑Bucket Rate Limiter Implements burst‑tolerant rate limiting using Redis + Lua. Working principle Tokens are generated at a fixed rate; each request consumes a token; request is rejected when no token is available. <code>@Component public class RateLimiterService { private final StringRedisTemplate redisTemplate; public RateLimiterService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } private static final String LUA_SCRIPT = """ local key = KEYS[1] local limit = tonumber(ARGV[1]) local interval = tonumber(ARGV[2]) local current = redis.call('get', key) if current and tonumber(current) >= limit then return 0 else redis.call('incr', key) redis.call('expire', key, interval) return 1 end """; public boolean tryAcquire(String key, int limit, int intervalSec) { DefaultRedisScript&lt;Long&gt; script = new DefaultRedisScript&lt;&gt;(LUA_SCRIPT, Long.class); Long result = redisTemplate.execute(script, Collections.singletonList(key), limit, intervalSec); return result != null && result == 1L; } } </code> Pros Smoothly handles bursts, simple implementation. Cons For finer‑grained control combine with a sliding‑window algorithm. Applicable scenarios API rate limiting, anti‑fraud, flash‑sale traffic control. Bitmap Statistics Bitmap stores boolean data with extremely low memory, suitable for massive lightweight counting. Typical uses Daily active user (DAU) counting. Sign‑in record: 365 bits per user for a year. <code>@Component public class BitmapService { private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final long SIGN_KEY_EXPIRE_DAY = 90L; private final StringRedisTemplate redisTemplate; public BitmapService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public void signIn(Long userId, LocalDate date) { String key = getSignKey(date); redisTemplate.opsForValue().setBit(key, userId, true); redisTemplate.expire(key, SIGN_KEY_EXPIRE_DAY, TimeUnit.DAYS); } public boolean hasSigned(Long userId, LocalDate date) { String key = getSignKey(date); return redisTemplate.opsForValue().getBit(key, userId); } public Long countSignIn(LocalDate date) { String key = getSignKey(date); byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8); return redisTemplate.execute((RedisCallback&lt;Long&gt;) conn -> conn.stringCommands().bitCount(keyBytes)); } private String getSignKey(LocalDate date) { return "sign:" + date.format(DATE_FORMATTER); } } </code> Pros Approximately 12 MB for 100 million users; fast operations. Cons Only binary state (0/1). Applicable scenarios User sign‑in tracking, online status monitoring. HyperLogLog Provides cardinality estimation with fixed ~12 KB memory and ~0.81 % error. <code>@Component public class UVService { private final StringRedisTemplate redisTemplate; public UVService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public void addVisit(String date, String userId) { String key = "uv:" + date; redisTemplate.opsForHyperLogLog().add(key, userId); } public Long countUV(String date) { String key = "uv:" + date; return redisTemplate.opsForHyperLogLog().size(key); } public Long countWeeklyUV(List&lt;String&gt; dates) { String destKey = "uv:weekly:" + LocalDate.now(); for (String d : dates) { redisTemplate.opsForHyperLogLog().union(destKey, "uv:" + d); } return redisTemplate.opsForHyperLogLog().size(destKey); } } </code> Pros Fixed memory, suitable for massive deduplication. Cons Returns an estimate; cannot query individual elements. Applicable scenarios Unique visitor counting, traffic analysis, large‑scale dedup. GEO Module Since Redis 3.2, GEO enables location‑based queries using sorted sets and GeoHash encoding. <code>@Component public class GeoService { private final StringRedisTemplate redisTemplate; public GeoService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public void addStore(Long storeId, double lng, double lat) { String key = "stores:geo"; redisTemplate.opsForGeo().add(key, new Point(lng, lat), storeId.toString()); } public List&lt;Store&gt; findNearbyStores(double lng, double lat, double radiusKm) { String key = "stores:geo"; Circle circle = new Circle(new Point(lng, lat), new Distance(radiusKm, Metrics.KILOMETERS)); GeoResults&lt;RedisGeoCommands.GeoLocation&lt;Object&gt;&gt; results = redisTemplate.opsForGeo().radius(key, circle); // Convert results to Store objects … return new ArrayList&lt;&gt;(); } public Distance distanceBetweenStores(Long id1, Long id2) { String key = "stores:geo"; return redisTemplate.opsForGeo().distance(key, id1.toString(), id2.toString()); } } </code> Pros Rich geo queries, precise distance calculation. Cons Accuracy limited by GeoHash precision; updating locations may require re‑indexing. Applicable scenarios Food‑delivery rider dispatch, nearby shop recommendation, ride‑hailing matching. Stream Message Queue Redis 5.0 Streams provide a reliable MQ‑like structure with consumer groups, acknowledgments, and history replay. <code>@Component public class StreamService { private final RedissonClient redissonClient; private final RStream&lt;String, String&gt; stream; public StreamService(RedissonClient redissonClient) { this.redissonClient = redissonClient; this.stream = redissonClient.getStream("order-stream"); this.stream.createGroup("order-group", StreamMessageId.AUTO); } public void publish(String orderId) { Map&lt;String, String&gt; data = new HashMap&lt;&gt;(); data.put("orderId", orderId); data.put("timestamp", String.valueOf(System.currentTimeMillis())); stream.add(data); } @Async public void consume() { while (true) { Map&lt;StreamMessageId, Map&lt;String, String&gt;&gt; msgs = stream.readGroup("order-group", "consumer-1", 10); for (Map.Entry&lt;StreamMessageId, Map&lt;String, String&gt;&gt; e : msgs.entrySet()) { process(e.getValue()); stream.ack("order-group", e.getKey()); } if (msgs.isEmpty()) { try { Thread.sleep(1000); } catch (InterruptedException ignored) {} } } } } </code> Pros Persistence, consumer groups, acknowledgments, replay. Cons Feature set lighter than dedicated MQ systems; best for lightweight scenarios. Applicable scenarios Task queues, log collection, notification systems. Lua Scripts Lua scripts allow multiple Redis commands to execute atomically, suitable for complex composite operations such as stock deduction, conditional locks, or advanced aggregations. Stock deduction with pre‑check to avoid overselling. Conditional distributed lock. Complex data aggregation. RedisJSON RedisJSON module stores JSON documents directly in Redis, supporting fine‑grained field operations. Installation Load as a module (included in Redis Stack) or compile and load manually. <code>@Component public class RedisJsonService { private final StringRedisTemplate redisTemplate; public RedisJsonService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public void saveUser(Long userId, User user) { String key = "user:" + userId; // In production use RedisJSON API (e.g., Lettuce or Redisson JSON commands) redisTemplate.opsForValue().set(key, user); } public void updateUserAge(Long userId, int age) { // Example: JSON.SET key $.age age (client‑specific implementation) } } </code> Pros Direct field‑level JSON manipulation; with RediSearch can index and query JSON. Cons Requires extra module; complex JSON increases memory usage. Applicable scenarios User configuration, session data, dynamic form storage. Conclusion The ten advanced Redis patterns—Bloom filter, Redisson lock, delayed queue, token‑bucket limiter, bitmap, HyperLogLog, GEO, Stream, Lua scripts, and RedisJSON—extend Redis beyond a simple cache, enabling higher performance, better scalability, and stronger reliability in Spring Boot 3.5 applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

HyperLogLogRedisBitmapDistributed LockBloom FilterToken BucketRedissonGEO
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

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.