Quiz
Six scenarios where the right Redis primitive matters. Each gives you a problem; pick the data structure / command and explain why. Answers below.
Six Redis design questions
EXAMPLE
# ============================================================
# Q1) Rate limit 60 req/min per IP, fixed window
# ============================================================
# ANSWER: INCR + EXPIRE on a key whose name embeds the current 60s bucket.
# key = 'rl:' + ip + ':' + Math.floor(now / 60_000)
# On first INCR (=1) set EXPIRE 60. Reject when count > 60.
# Why: O(1), bounded memory (one key per IP per minute), TTL-cleans itself.
# ============================================================
# Q2) Leaderboard with friend list filtering (top 10 within a group)
# ============================================================
# ANSWER: ZSET per group.
# ZADD lb:weekly:friends:42 <score> <user>
# ZREVRANGE lb:weekly:friends:42 0 9 WITHSCORES
# Why: O(log N) inserts, O(log N + M) range reads, sorted naturally by score.
# ============================================================
# Q3) Cache user session state with sliding expiry
# ============================================================
# ANSWER: HASH for the fields + EXPIRE that slides on every read.
# HSET sess:<id> user_id 42 plan pro
# HGETALL sess:<id>
# EXPIRE sess:<id> 1209600 (slide TTL on read)
# Why: per-field updates, single round trip, sliding TTL via re-EXPIRE.
# ============================================================
# Q4) De-dupe identical messages over a moving 24h window
# ============================================================
# ANSWER: SET NX with TTL.
# SET dedupe:<hash> 1 NX EX 86400
# If the SET returns OK -> first time, process. If it returns null -> duplicate, skip.
# Why: atomic, O(1), self-expiring. Memory bounded by 24h x rate.
# ============================================================
# Q5) Approximate unique daily visitor counts
# ============================================================
# ANSWER: HyperLogLog.
# PFADD visitors:2026-06-18 <user> -> O(1)
# PFCOUNT visitors:2026-06-18 -> O(1)
# Why: ~0.81% error at ~12KB per key, vs O(N) for an exact SET-based count.
# Merge across days with PFCOUNT visitors:2026-06-15 visitors:2026-06-16 ...
# ============================================================
# Q6) Job queue with at-least-once delivery + retries
# ============================================================
# ANSWER: Streams + Consumer Groups (XADD + XREADGROUP + XACK)
# Why: Streams are durable, support multiple consumers, track pending entries
# per consumer for retries, and survive restarts. Plain PUBSUB has no replay
# and plain LIST queues need hand-rolled retry tracking.
# XADD jobs * payload '{...}'
# XGROUP CREATE jobs g1 $ MKSTREAM
# XREADGROUP GROUP g1 consumer-1 COUNT 10 BLOCK 5000 STREAMS jobs >
# XACK jobs g1 <id> (on success)
# Lost / stuck entries appear in XPENDING — re-deliver to another consumer.
# ============================================================
# Bonus — the WRONG choices to avoid
# ============================================================
# - PUBSUB for durable job delivery -> no replay, fire and forget
# - Plain LIST for rate limiting -> O(N) cleanup, no sliding-window semantics
# - SETs for leaderboards -> no scores, no ordering
# - Storing 1MB JSON blobs in a string -> Redis is in-memory; that bites the budget
# Scoring
# 6 / 6 -> design reviews are quick conversations
# 4 / 6 -> bookmark the redis/cheatsheet
# < 4 -> read the data-types section of redis.io
Why it matters
Reach for HyperLogLog whenever the answer to "how many unique X?" is fine within 1%. The memory savings vs an exact SET are enormous — ~12KB no matter the cardinality — and the merge property (PFMERGE across day-keys) gives you free roll-ups for weekly/monthly counts without re-computing from raw events.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…