Redis patterns: caching, counters, rate limits, queues and leaderboards
Redis is a Swiss army knife for backend work. Here are the patterns that solve real problems, and the mistakes to avoid.

Redis is an in-memory data store with useful data structures. These patterns cover most real uses.
1. Cache (cache-aside)
value = redis.get(key)
if value is missing:
value = database.query(...)
redis.set(key, value, ex=300) # expires in 5 minutes
Always set a TTL, and delete or update the key when the source changes. Add random jitter to TTLs to avoid mass expiry.
2. Counters
INCR page:views:42 is atomic, so many servers can count safely with no race conditions. Use it for page views, likes and quotas. Write the totals to your main database periodically if you need permanent records.
3. Rate limiting
Use INCR on a key like rate:user42:2026-10-25T10:15 and EXPIRE it to the window length. If the count passes the limit, reject. For smoother limits use a sorted set (sliding window) or a token bucket in a Lua script so the check and update are atomic.
4. Leaderboards and rankings
A sorted set keeps members ordered by score:
ZINCRBY leaderboard 10 "player:7"
ZREVRANGE leaderboard 0 9 WITHSCORES # top 10
ZREVRANK leaderboard "player:7" # a player's rank
All operations are fast (logarithmic). The same idea works for "most viewed articles" (this site keeps its view counts in a sorted set).
5. Sessions
Store session data under a random session ID with a TTL. Fast, shared across servers, and expiry is built in.
6. Queues and streams
A list (LPUSH / BRPOP) makes a simple job queue. Streams add consumer groups, acknowledgements and replay, closer to a real message queue. For serious workloads consider Kafka or RabbitMQ, but Redis is enough for many background jobs.
7. Pub/sub
Publish messages to a channel and subscribers receive them instantly. Good for real-time notifications between servers. Messages are not stored: a subscriber that is offline misses them.
8. Distributed lock
SET lock:job <id> NX PX 30000, release with a script that checks the owner. Fine for avoiding duplicate work, but not a guarantee of correctness (see the distributed lock part).
Pitfalls
- Memory is limited. Set
maxmemoryand an eviction policy, or Redis may use all RAM. - Persistence is not a database's durability. A crash can lose recent writes depending on settings. Keep the source of truth elsewhere unless you configure it carefully.
- Big keys and slow commands (like
KEYS *) block everyone, because commands run on one thread. UseSCAN. - Key naming: use a clear scheme such as
app:object:id:field. - Security: never expose Redis to the internet. Bind to a private address, set a password and restrict commands.
Takeaway: use Redis for fast, temporary or derived data (caches, counters, limits, rankings, sessions, light queues), keep the source of truth in your database, and protect memory and access.
Backend & Database series, Part 2 (performance and operations): 6 of 6. Previous: Safe database migrations without downtime.


