Redis Patterns (Pub/Sub, Sorted Sets, Lua)
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7), since redis-insight and laravel-debugbar can surface N+1 Redis calls or missing TTLs at runtime, but no automated linter flags misuse patterns like KEYS * or missing pipelines.
Closest to 'touches multiple files / significant refactor' (e5), as switching from per-call requests to pipelines, adding TTLs, or replacing KEYS with SCAN typically touches several cache/queue modules, not just one line.
Closest to 'persistent productivity tax' (b5), because Redis usage spans web/cli/queue-worker contexts and patterns chosen (data structures, persistence config) affect many work streams across the codebase.
Closest to 'notable trap most devs eventually learn' (t5), grounded in the misconception that Redis is just a faster Memcached — devs miss its rich data structures and footguns like KEYS * blocking or missing TTLs causing eviction.
Also Known As
TL;DR
Explanation
Redis data structures enable sophisticated patterns: Sorted Sets (ZADD/ZRANGE) for leaderboards and priority queues; Lists (LPUSH/BRPOP) for FIFO job queues; Sets for unique visitor counting; Hashes for session storage; INCR/EXPIRE for atomic rate limiting counters; Pub/Sub for real-time notifications; Lua scripts for atomic multi-step operations without round-trips; and SET key value NX EX for distributed locks (Redlock for multi-node). Redis Streams (XADD/XREAD) provide durable message queues with consumer groups, persistent delivery, and acknowledgement. PHP clients: Predis (pure PHP) and phpredis (C extension, faster).
Common Misconception
Why It Matters
Common Mistakes
- Using Redis as a primary database without persistence configured — data is lost on restart without RDB/AOF.
- Not setting TTLs on cached keys — Redis fills memory and starts evicting keys unpredictably.
- Using KEYS * in production — it blocks Redis while scanning all keys; use SCAN instead.
- Not using pipelines for multiple sequential Redis commands — each round trip adds latency.
Code Examples
// N sequential Redis calls — N round trips:
foreach ($userIds as $id) {
$name = $redis->get("user:$id:name"); // 1 round trip per user
}
// Pipeline — 1 round trip for all:
$pipe = $redis->pipeline();
foreach ($userIds as $id) { $pipe->get("user:$id:name"); }
$names = $pipe->execute();
// String — simple cache
$redis->set('user:42:name', 'Alice', ['ex' => 300]);
// Hash — object storage without serialisation
$redis->hSet('user:42', 'name', 'Alice');
$redis->hSet('user:42', 'email', 'alice@example.com');
$name = $redis->hGet('user:42', 'name');
// Sorted set — leaderboard
$redis->zAdd('leaderboard', 1500, 'alice');
$top10 = $redis->zRevRange('leaderboard', 0, 9, true); // with scores
// List — simple queue
$redis->lPush('email_queue', json_encode($message));
$job = $redis->rPop('email_queue');
// Atomic counter — rate limiting
$redis->incr('api_hits:' . date('YmdH') . ':' . $ip);