Redis Fundamentals
In-memory data store for low-latency caching, counters, coordination, and realtime patterns.
Problem it solves
- Primary databases can become bottlenecks for hot reads and bursty traffic.
- Many systems need fast shared counters, TTL state, and lightweight coordination.
- Redis provides low-latency in-memory primitives to offload core systems and improve responsiveness.
Definition
Redis is an in-memory key-value data store with optional persistence and rich data structures (strings, hashes, lists, sets, sorted sets, streams, bitmaps, HyperLogLog).
Why It Matters
- Offloads hot reads from primary databases and reduces query latency.
- Supports atomic operations for counters, TTL-based state, and distributed coordination.
- Enables building realtime features (leaderboards, session state, pub/sub style notifications).
When to Use
- High-read APIs where DB offload and low latency are critical.
- Short-lived session/token/state storage with TTL.
- Fast counters, quotas, and distributed coordination primitives.
- Leaderboard/realtime features using sorted sets/streams.
When NOT to Use
- As the only durable store for critical financial data without appropriate persistence strategy.
- Large analytical queries better suited for columnar/OLAP systems.
- Use cases where eventual cache staleness is unacceptable without explicit invalidation strategy.
Code Variations
String key = "user:" + userId;
String cached = redis.get(key);
if (cached != null) return deserialize(cached);
User user = userRepository.findById(userId).orElseThrow();
redis.setex(key, 300, serialize(user)); // 5 min TTL
return user;String key = "rl:" + userId + ":" + epochMinute();
long count = redis.incr(key);
if (count == 1) redis.expire(key, 120); // keep for 2 mins
if (count > 100) throw new TooManyRequestsException();String lockKey = "lock:order:" + orderId;
String owner = UUID.randomUUID().toString();
boolean acquired = redis.set(lockKey, owner, SetArgs.setArgs().nx().px(10000)) != null;
if (!acquired) return;
try {
processOrder(orderId);
} finally {
// Unlock only if still owner (Lua compare-and-del)
redis.eval(UNLOCK_LUA, 1, lockKey, owner);
}- Eviction policy: allkeys-lru / volatile-ttl based on workload
- Persistence: RDB/AOF strategy by durability need
- Memory alarms: maxmemory + alerting
- Replication/failover: Sentinel or managed service
- Key naming: namespace prefixes for ownership clarityWhy Redis vs only using relational DB
| Aspect | Only Relational DB | Relational DB + Redis |
|---|---|---|
| Hot read latency | Higher under load | Very low for cached keys |
| Burst handling | DB can become bottleneck | Redis absorbs read spikes |
| Ephemeral state | Extra schema/cleanup logic | Natural with TTL keys |
| Atomic counters/rate control | Possible but heavier | Simple atomic ops (INCR, Lua, transactions) |
| Cost/risk | Simpler stack | Extra component to operate correctly |
Common Confusions Cleared Up
Redis is often best as acceleration/coordination layer. Your primary DB usually remains source of truth for durable business state.
Pub/Sub is fire-and-forget and non-durable to offline consumers. Streams provide persisted event log with consumer groups and ack semantics.
As soon as coordination/locking spans failures and partitions, correctness requires stronger patterns (timeouts, ownership, fencing, retries).
Variations / Implementations
1) Cache-aside pattern
Read path: check Redis first, fallback to DB on miss, then fill cache with TTL. This is the most common Redis use case.
2) Rate limiting (token/fixed window)
Use atomic increments + TTL or Lua scripts to enforce per-user/IP quotas efficiently.
3) Distributed lock (carefully)
Use SET key value NX PX ttl and verify ownership on unlock. Pair with fencing/timeout strategy for correctness-sensitive flows.
4) Realtime data structures
Sorted sets for leaderboards, hashes for profile/session maps, streams for consumer groups.
Common Mistakes / Anti-Patterns
- No TTL for cache keys (memory growth + stale data).
- Cache stampede on hot-key misses without lock/coalescing.
- Blind
DELduring lock release (can unlock someone else). - Oversized values and unbounded key cardinality.
- No monitoring of hit-rate, memory, evictions, and latency.