Skip to content
All articles
RedisCaching

Redis Patterns Every Full-Stack Dev Should Know

Caching, pub/sub, rate limiting, and session management — from someone who uses Redis daily.

3 February 20269 min read

Redis Is Not Just a Cache

Most developers first encounter Redis as a caching layer — stick it in front of your database, reduce load, move on. That's a valid use case, but it barely scratches the surface. At Flipkart, Redis is the backbone of several real-time systems that have nothing to do with caching.

I think of Redis as a Swiss Army knife for ephemeral data. If your data is temporary, time-sensitive, or needs sub-millisecond access, Redis probably has a data structure that fits. The trick is knowing which structure to reach for.

Cache-Aside with TTL Jitter

The basic cache-aside pattern is simple: check Redis first, fall back to the database, write the result back to Redis. But the naive implementation has a thundering herd problem — when a popular key expires, hundreds of requests simultaneously hit your database.

At Flipkart, we solve this with TTL jitter. Instead of setting every cache entry to expire in exactly 300 seconds, we add a random offset of plus or minus 30 seconds. This spreads cache expiration across time and prevents stampedes. We also use a mutex pattern where the first request to find an expired key acquires a lock and refreshes the cache while others serve stale data.

The combination of jitter and mutex reduced our database load by roughly 40% during peak traffic compared to basic cache-aside. It's a small implementation detail with an outsized impact.

Rate Limiting with Sliding Windows

Fixed-window rate limiting is easy to implement but has a well-known edge case: a burst of requests at the boundary between two windows can exceed your intended limit. Sliding window rate limiting solves this, and Redis sorted sets make it elegant.

The pattern is straightforward. Use ZADD to add each request timestamp to a sorted set keyed by the client identifier. Use ZREMRANGEBYSCORE to remove entries older than your window. Use ZCARD to count remaining entries. If the count exceeds your limit, reject the request. Set an expiry on the key equal to your window size so abandoned keys don't leak memory.

We use this at Flipkart for API rate limiting on internal services. The beauty is that it works across distributed instances because Redis is the single source of truth. No need for local counters or sticky sessions.

Pub/Sub for Real-Time Updates

Redis pub/sub is underrated for small to medium scale real-time features. If you need WebSocket-like push updates but don't want to operate a dedicated message broker, Redis pub/sub gets you 80% of the way there.

The caveat is that Redis pub/sub is fire-and-forget. If a subscriber is disconnected when a message is published, that message is lost. For use cases where message durability matters, use Redis Streams instead. Streams give you consumer groups, acknowledgment, and replay — essentially a lightweight Kafka for teams that don't need Kafka's complexity.

Sorted Sets for Leaderboards and Feeds

Sorted sets are my favorite Redis data structure. They maintain elements in order by score, and operations like ZRANGEBYSCORE and ZREVRANGE are O(log N). This makes them perfect for leaderboards, activity feeds, and priority queues.

At CARS24, we used sorted sets to power a recently-viewed cars feature. Each user had a sorted set keyed by their user ID, with car IDs as members and view timestamps as scores. Fetching the 10 most recently viewed cars was a single ZREVRANGE call. Adding a new view was ZADD with the current timestamp. We capped the set at 50 entries using ZREMRANGEBYRANK to prevent unbounded growth.

The whole feature — API, caching, and cleanup — took less than a day to implement. Try doing that with a relational database and you'll spend more time writing the query than building the feature.

Mistakes I Have Made with Redis

The biggest mistake I made early on was treating Redis as a primary data store. Redis is persistent if you configure it that way, but it's not designed to be your source of truth. Use it for data you can afford to lose or rebuild. If your application breaks when Redis goes down, you have an architecture problem.

The second mistake was not monitoring memory usage closely enough. Redis stores everything in memory, and a runaway key pattern can eat your entire allocation in minutes. Set maxmemory and a sensible eviction policy from day one. At Flipkart we use allkeys-lfu as the default eviction policy, which works well for most workloads.

The third mistake was using KEYS in production. Never do this. It scans the entire keyspace and blocks the server. Use SCAN instead. I learned this the hard way at Mamaearth when a debugging session with KEYS caused a 2-second latency spike across the platform.

Found this useful? I write about engineering, performance, and career growth.