QuizCluster
DatabasesBackend Engineer to Staff Systems Architect17 min read

Redis System Design Guide: Caching, Eviction, Persistence & Distributed Locks

From Data Structure Internals to Redlock, Redis Cluster & Production-Grade Caching Architecture

Priya Nataraj
Staff Data Engineer & Distributed Caching Specialist
11+ Years Building High-Throughput Caching & Data Platforms
Prep Timeline
3 to 5 Weeks
Format
System Design, Backend Deep-Dive, Database Internals
Conversion
+74% System Design Round Confidence
Redis System Design Guide: Caching, Eviction, Persistence & Distributed Locks
Executive Summary & Key Takeaways

What You Must Master to Clear This Track

  • Know the exact complexity and internal encoding of Strings, Hashes, Sorted Sets, and Streams so you can justify data structure choices under load.
  • Distinguish cache-aside, write-through, and write-behind by who owns writing to the cache and what staleness or data-loss window each accepts.
  • Explain eviction policy trade-offs (LRU vs LFU vs TTL-based) and why the default noeviction policy silently rejects writes once maxmemory is hit.
  • Articulate the RDB vs AOF durability trade-off: RDB is fast to restore but loses minutes of data, AOF with everysec loses at most one second but is slower to replay.
  • Understand that Redis Cluster shards via 16384 hash slots (not consistent hashing) and that Redlock trades perfect safety for pragmatic multi-instance liveness.
Structured Preparation Timeline

Step-by-Step Study Plan

Follow this sequential roadmap designed to take you from core foundations to advanced architecture and mock interviews.

Phase 1 (Week 1)

Data Structure Selection & Complexity Analysis

Core Data Structures & In-Memory Fundamentals

Strings, Hashes, Lists, Sets, Sorted Sets, and Streams, including their internal encodings (listpack/ziplist, skip list + hash table) and when to reach for each.

Key Milestones
  • Explain why ZSET uses a skip list plus hash table to give O(log N) ZADD/ZRANGE and O(1) ZSCORE lookups simultaneously.
  • Model a leaderboard, a rate limiter, and a session store using the right primitive for each.
  • Understand Streams (XADD, consumer groups, XACK/XPENDING) as a lightweight Kafka alternative for at-least-once delivery.
Recommended Actions
  • Run MEMORY USAGE and OBJECT ENCODING on real keys to see listpack vs hashtable/skiplist transitions.
  • Practice explaining Big-O for at least 6 commands per data type out loud.
Phase 2 (Week 2)

Cache Consistency Strategies & Durability Trade-offs

Caching Patterns, Eviction & Persistence

Cache-aside, write-through, and write-behind patterns; LRU/LFU/TTL eviction policies under memory pressure; RDB snapshotting vs AOF durability.

Key Milestones
  • Draw the full cache-aside read/write path including cache stampede protection.
  • Compare maxmemory-policy options and pick the correct one for a session cache vs a computed-results cache.
  • Explain fork() + copy-on-write for BGSAVE and appendfsync always/everysec/no trade-offs for AOF.
Recommended Actions
  • Configure a local Redis instance with maxmemory and allkeys-lfu, then observe eviction under synthetic load.
  • Enable AOF with appendfsync everysec and inspect the rewrite log to understand compaction.
Phase 3 (Weeks 3-4)

High Availability, Sharding & Redlock

Replication, Cluster Topology & Distributed Coordination

Sentinel-based failover, Redis Cluster's 16384 hash slots, cross-slot operation limitations, Redlock distributed locking, and Redis-backed rate limiting.

Key Milestones
  • Trace a Sentinel quorum failover from primary failure detection to replica promotion.
  • Explain hash slot routing, MOVED/ASK redirection, and resharding in Redis Cluster.
  • Implement a Redlock-style lock across 3-5 independent Redis instances with a majority quorum and safe release via Lua.
Recommended Actions
  • Practice deriving RPS, memory footprint, and shard count for a 50M-user session store on a whiteboard.
  • Discuss known Redlock criticisms (clock drift, GC pauses) and how fencing tokens mitigate them.
Deep-Dive Architecture & Concepts

1. Redis Core Data Structures & Time Complexity

Redis is fundamentally an in-memory data structure server, not just a key-value cache. Picking the right structure for the access pattern is what separates a naive cache from a well-designed one.

Strings

O(1) GET/SET/INCR. Backed by Simple Dynamic Strings (SDS); small integers use a shared object pool. Ideal for counters, feature flags, and serialized cache blobs (JSON/Protobuf).

Hashes

O(1) HGET/HSET/HDEL. Encoded as a compact listpack for small field counts, converting to a full hash table past hash-max-listpack-entries. Ideal for storing an object's fields (a user profile) without a full JSON deserialize.

Sorted Sets (ZSET)

O(log N) ZADD/ZRANGE/ZRANK via a skip list combined with a hash table for O(1) score lookups. Ideal for leaderboards, priority queues, and sliding-window rate limiters keyed by timestamp score.

Streams

O(1) amortized XADD append-only log with consumer groups, XACK, and XPENDING for at-least-once delivery. Ideal for event sourcing, activity feeds, and lightweight pub/sub replacements that need replay and backpressure.

Lists & Sets

Lists (O(1) LPUSH/RPUSH, O(N) LINDEX) work well as bounded queues; Sets (O(1) SADD/SISMEMBER) are ideal for deduplication, tagging, and fast membership checks like unique-visitor tracking.

Interviewer Insights & Pro Tips
  • Run OBJECT ENCODING <key> in interviews-style discussion to show you understand that small collections silently use compact encodings (listpack) before promoting to hash tables or skip lists.
  • Prefer Hashes over storing one String key per object field — it collapses N keys into 1, cutting memory overhead from per-key bookkeeping.
Red Flags & Common Pitfalls
  • Using a single giant String (a multi-MB JSON blob) as a hot key — Redis is single-threaded per command, so large value serialization/deserialization blocks the event loop.
  • Choosing a List for a queue that needs random access or dedup — Lists have O(N) LINDEX/LREM, which quietly becomes a bottleneck as it grows.
Deep-Dive Architecture & Concepts

2. Caching Patterns: Cache-Aside, Write-Through, Write-Behind & Eviction

The caching pattern you choose determines who is responsible for cache population, how stale reads can get, and what happens to writes during a cache outage.

Cache-Aside (Lazy Loading)

Application code checks the cache first; on a miss it reads the DB and populates the cache with a TTL. Simplest and most common pattern — cache only holds what's actually requested, but the first request after a miss always pays the full DB latency.

Write-Through

Every write goes through the cache, which synchronously writes to the DB before acknowledging. Guarantees cache and DB never diverge, at the cost of added write latency on every request.

Write-Behind (Write-Back)

Writes land in the cache and are asynchronously flushed to the DB in batches. Lowest write latency and highest throughput, but risks data loss if the cache crashes before the flush completes.

Eviction Policies Under Memory Pressure

allkeys-lru/allkeys-lfu approximate true LRU/LFU using random sampling (not a full linked list) for O(1)-ish eviction; volatile-ttl evicts keys closest to expiry first; noeviction (the default) rejects writes outright once maxmemory is reached.

Cache-Aside Read/Write Lifecycle

The request path an application follows on a cache miss versus a subsequent cache hit.

1
Client Read Request
App server receives a request for a product and computes the cache key (e.g. product:1042).
2
Cache Lookup (GET)
Redis is queried first; on a hit, the serialized value is returned immediately with sub-millisecond latency.
3
Cache Miss -> DB Query
On a miss, the app queries the primary database (or a read replica) for the authoritative record.
4
Populate Cache with TTL
The result is written back to Redis with an expiry (plus jitter) so future reads hit the cache and stale data self-heals.
5
Return to Client
The response is returned to the caller; subsequent requests for the same key are served entirely from memory until TTL expiry or invalidation.
Cache-Aside Read Path with Stampede Protection (TTL Jitter + Mutex)
typescript
import { redis } from "./redisClient";
  import { db } from "./db";
  
  const TTL_SECONDS = 300;
  const JITTER_SECONDS = 30;
  
  async function getProduct(productId: string) {
    const cacheKey = `product:${productId}`;
    const cached = await redis.get(cacheKey);
    if (cached) return JSON.parse(cached);
  
    // Prevent cache stampede: only one caller rebuilds a hot key
    const lockKey = `lock:${cacheKey}`;
    const acquiredLock = await redis.set(lockKey, "1", "NX", "EX", 5);
  
    if (!acquiredLock) {
      // Another request is already rebuilding; brief backoff then retry read
      await new Promise((r) => setTimeout(r, 50));
      return getProduct(productId);
    }
  
    try {
      const product = await db.products.findById(productId);
      if (product) {
        const ttl = TTL_SECONDS + Math.floor(Math.random() * JITTER_SECONDS);
        await redis.set(cacheKey, JSON.stringify(product), "EX", ttl);
      }
      return product;
    } finally {
      await redis.del(lockKey);
    }
  }
Why it matters: Adding random jitter to the TTL prevents many keys from expiring at the exact same millisecond (thundering herd), and the short-lived NX lock ensures only one request rebuilds a given hot key while others wait instead of all hammering the DB simultaneously.
Interviewer Insights & Pro Tips
  • For write-heavy workloads with tolerable data-loss windows (e.g. view counters, analytics), write-behind batching to the DB can cut write amplification by an order of magnitude.
  • Always set an explicit maxmemory-policy — leaving the default noeviction on a pure cache instance means Redis starts returning OOM errors on writes instead of evicting old data.
Red Flags & Common Pitfalls
  • Forgetting to invalidate or update the cache key on a write path in cache-aside, leaving stale data served until TTL expiry.
  • Using write-through for a cold, rarely-read dataset — you pay synchronous write cost for data that may never be read from cache again.
Deep-Dive Architecture & Concepts

3. Persistence: RDB Snapshots vs AOF & Durability Trade-offs

Redis is in-memory first, but production deployments almost always need a durability story for restarts and crash recovery — the choice between RDB and AOF is a direct trade-off between recovery speed and data-loss window.

RDB (Point-in-Time Snapshots)

SAVE/BGSAVE forks the process and uses copy-on-write to write a compact binary snapshot without blocking the main event loop. Fast to load on restart, but any writes since the last snapshot (seconds to minutes) are lost on a crash.

AOF (Append-Only File)

Logs every write command; appendfsync controls durability: always (fsync every write, safest, slowest), everysec (fsync once per second, default, loses at most ~1s), no (OS-controlled, fastest, least safe).

AOF Rewrite / Compaction

Over time the AOF log grows unbounded; BGREWRITEAOF forks and rewrites it as the minimal set of commands needed to reconstruct current state, similar in mechanism to RDB's copy-on-write fork.

Hybrid Persistence (RDB + AOF)

Redis 4+ can prefix the AOF file with an RDB-formatted snapshot on rewrite, combining RDB's fast restart with AOF's minimal data-loss window — the recommended default for most production deployments.

Interviewer Insights & Pro Tips
  • For a pure cache tier where the DB is the source of truth, disable persistence entirely (save "", appendonly no) — losing the cache is cheap, and you avoid fork-related latency spikes on a large dataset.
  • For Redis used as a system of record (queues, session stores without a backing DB), enable hybrid persistence with appendfsync everysec as the default balance.
Red Flags & Common Pitfalls
  • Running BGSAVE on a host with insufficient free memory — copy-on-write can double memory usage under heavy write load during the fork, triggering OOM kills.
  • Assuming appendfsync always is 'safe' without measuring latency impact — it fsyncs on every single write and can drop throughput by 10x or more on spinning or network-attached disks.
Deep-Dive Architecture & Concepts

4. Replication, High Availability, Distributed Locks & Rate Limiting

Beyond a single node, production Redis needs a failover story (Sentinel), a sharding story (Cluster), and often distributed coordination primitives (Redlock) layered on top.

Asynchronous Replication

Primary replicates to replicas asynchronously by default; replicas can serve reads but may lag behind, so a failover can lose the last few unacknowledged writes (an AP-leaning trade-off, not full CP consistency).

Sentinel: Automatic Failover

A quorum of independent Sentinel processes monitors primaries, agrees via majority vote that a primary is down, and promotes the most up-to-date replica — client libraries discover the new primary via Sentinel's pub/sub notifications.

Redis Cluster: Hash Slot Sharding

Data is partitioned across exactly 16384 hash slots (CRC16(key) mod 16384), each owned by one primary node; multi-key operations across slots fail with a CROSSSLOT error unless keys share a hash tag ({user123}:profile).

Redlock: Distributed Mutual Exclusion

Acquire a lock with the same key/value across N independent Redis masters (typically 5); the lock is considered held only if a majority (N/2+1) acknowledge within a bounded time budget, and release deletes the key only if the value still matches (via a Lua script) to avoid deleting someone else's lock.

Rate Limiting with Redis

Token bucket via INCR + EXPIRE for fixed windows, or a sliding-window log using a ZSET keyed by timestamp (ZADD + ZREMRANGEBYSCORE to evict old entries + ZCARD to count) for smoother, burst-resistant limiting.

Redis Cluster Hash Slot Routing

How a client request is routed to the correct shard using CRC16 hash slots, including redirection on resharding.

1
Client Computes Slot
Client (or a slot-aware library) computes CRC16(key) mod 16384 to determine the target hash slot.
2
Route to Owning Node
Request is sent directly to the primary node that owns that slot range, based on a locally cached cluster topology.
3
MOVED Redirection
If the slot has migrated to another node (permanent reassignment), that node returns a MOVED error with the correct address; the client updates its slot cache and retries.
4
ASK Redirection (Mid-Resharding)
If a slot is actively being migrated, the old node returns an ASK error for keys already moved, directing the client to retry against the new node with an ASKING flag.
5
Response Returned
Once routed correctly, the owning node executes the command and returns the result directly to the client.
Simplified Redlock: Acquire & Safe Release Across N Redis Masters
typescript
import { randomUUID } from "crypto";
  import type Redis from "ioredis";
  
  const LOCK_TTL_MS = 10_000;
  const DRIFT_FACTOR = 0.01;
  
  // Lua script: only delete the key if the value still matches our token
  const RELEASE_SCRIPT = `
  if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
  else
    return 0
  end
  `;
  
  async function acquireLock(clients: Redis[], resource: string) {
    const token = randomUUID();
    const quorum = Math.floor(clients.length / 2) + 1;
    const start = Date.now();
  
    let acquiredCount = 0;
    await Promise.all(
      clients.map(async (client) => {
        const ok = await client.set(resource, token, "PX", LOCK_TTL_MS, "NX");
        if (ok === "OK") acquiredCount++;
      })
    );
  
    const elapsed = Date.now() - start;
    const validityMs = LOCK_TTL_MS - elapsed - Math.round(LOCK_TTL_MS * DRIFT_FACTOR);
  
    if (acquiredCount >= quorum && validityMs > 0) {
      return { token, validityMs };
    }
  
    // Failed to reach quorum: release on every node before giving up
    await releaseLock(clients, resource, token);
    return null;
  }
  
  async function releaseLock(clients: Redis[], resource: string, token: string) {
    await Promise.all(clients.map((client) => client.eval(RELEASE_SCRIPT, 1, resource, token)));
  }
Why it matters: Requiring a majority quorum (not all N nodes) keeps the lock available if a minority of instances are down, while the compare-and-delete Lua script on release prevents a slow client from deleting a lock it no longer owns after its TTL expired and someone else acquired it.
Interviewer Insights & Pro Tips
  • Use hash tags like {order:5001}:items and {order:5001}:status to force related keys into the same slot so multi-key operations (MGET, transactions) don't hit CROSSSLOT errors.
  • For most single-datacenter use cases, a well-tuned Sentinel setup with WAIT for replica acknowledgment is simpler and sufficient — reach for Redlock only when you need cross-instance mutual exclusion, not just single-primary locking.
Red Flags & Common Pitfalls
  • Treating Redlock as a perfect distributed consensus mechanism — under process pauses (GC, VM stop-the-world) or clock jumps, two clients can briefly believe they both hold the lock; use fencing tokens on the protected resource for true safety.
  • Running Redis Cluster with only 3 nodes and no replicas — losing a single primary before its slot range is recovered causes cluster-wide unavailability for that slot range.
Real-World Example

Eliminating Overselling and Database Overload During Flash Sales at a Mid-Size E-Commerce Platform

A mid-size e-commerce company's flagship flash-sale events routinely overwhelmed their primary MySQL read replicas, causing checkout latency spikes above 4 seconds and, worse, occasional overselling of limited-inventory SKUs when multiple app instances decremented stock concurrently without coordination.

  • 1Introduced a cache-aside layer in front of product catalog reads using Redis, with a 30-second TTL plus randomized jitter to prevent synchronized mass expiry across thousands of SKU keys.
  • 2Added a short-lived per-key mutex (SET NX PX) so that on a cache miss for a suddenly hot product, only one request rebuilt the cache entry while concurrent requests waited briefly and retried, eliminating stampede-driven DB spikes.
  • 3Replaced ad-hoc application-level inventory checks with a Redlock-based distributed lock across a 5-node Redis quorum to serialize stock-decrement operations per SKU across all app server instances.
  • 4Migrated session storage from sticky in-memory sessions to a Redis Cluster deployment sharded via hash slots, enabling horizontal scaling of app servers without session-affinity constraints.
  • 5Configured Sentinel-based automatic failover for the lock and session Redis tiers, with WAIT-based replica acknowledgment on critical inventory-lock writes to reduce the risk of losing a lock state during a primary failover mid-sale.
Outcome: Database read load during flash sales dropped by roughly 92%, checkout latency stabilized under 300ms at peak, and overselling incidents dropped to zero across the following three flash-sale events.
Real-World Interview Questions

Top Must-Know Interview Questions & Model Answers

Data StructuresHard

Q1: Why does Redis use a skip list combined with a hash table for Sorted Sets instead of just a balanced tree?

Executive Answer:The hash table gives O(1) score lookups by member (ZSCORE), while the skip list gives O(log N) ordered range operations (ZRANGE, ZRANK) — a single tree structure can't cheaply give you both without extra bookkeeping.
Deep Dive Analysis:
  • A skip list is simpler to implement correctly for range queries and concurrent-friendly traversal than a balanced tree, with comparable O(log N) average-case performance.
  • The parallel hash table maps member -> score directly, so checking or updating an individual member's score doesn't require walking the skip list at all.
  • This dual structure is why ZADD updates both structures atomically and why memory overhead for ZSETs is higher than for a plain hash.
Interviewer Takeaway: When a data structure needs both O(1) point lookups and O(log N) ordered range queries, consider a hash table paired with an ordered index rather than one general-purpose tree.
Data StructuresMedium

Q2: How would you model a real-time leaderboard for 10 million users using Redis?

Executive Answer:Use a single Sorted Set with user ID as member and score as the ranking metric; ZADD to update scores, ZREVRANGE for top-N, and ZREVRANK for a specific user's rank.
Deep Dive Analysis:
  • ZADD is O(log N), so updating a score on every game event scales well even at high write volume.
  • ZREVRANGE withscores 0 99 fetches the top 100 in O(log N + M); ZREVRANK gives any user's position in O(log N) without scanning the whole set.
  • For multi-region leaderboards, shard by game/tournament ID so each ZSET stays bounded rather than one global set across all users.
Interviewer Takeaway: Sorted Sets are the default answer whenever an interview mentions ranking, leaderboards, or 'top-K by some score.'
Data StructuresMedium

Q3: What is the practical difference between using Redis Lists and Redis Streams as a message queue?

Executive Answer:Lists give simple FIFO/LIFO semantics via LPUSH/BRPOP with no replay or multiple-consumer tracking; Streams add persistent IDs, consumer groups, and acknowledgment (XACK/XPENDING) for at-least-once delivery.
Deep Dive Analysis:
  • A List-based queue loses a message permanently once BRPOP returns it to a worker that then crashes before processing.
  • Streams retain entries until explicitly trimmed (XTRIM) and track per-consumer-group delivery, so a crashed worker's unacknowledged messages (XPENDING) can be claimed by another consumer (XCLAIM).
  • Streams are the closer analog to a lightweight Kafka partition; Lists are closer to a simple job queue with no replay guarantees.
Interviewer Takeaway: Reach for Streams over Lists whenever the interviewer asks about delivery guarantees, multiple consumers, or message replay.
Data StructuresMedium

Q4: Why should you avoid storing one very large String value (multiple megabytes) as a single Redis key?

Executive Answer:Redis executes commands on a single thread per event loop iteration; serializing, deserializing, or transferring a multi-MB value blocks that thread and stalls every other client's request during that time.
Deep Dive Analysis:
  • Even 'simple' GET/SET on a large blob costs real wall-clock time proportional to its size for network I/O and memory copy.
  • Splitting large objects into a Hash of smaller fields, or chunking into multiple keys, keeps individual command latency low and predictable.
Interviewer Takeaway: Treat any single-key value over roughly 100KB-1MB as a red flag in a system design interview and propose decomposition.
Data StructuresHard

Q5: What is the HyperLogLog data structure in Redis, and when would you use it over a Set?

Executive Answer:HyperLogLog is a probabilistic structure for approximate cardinality (unique count) estimation using only ~12KB regardless of how many elements are added, with roughly 0.81% standard error.
Deep Dive Analysis:
  • A Set storing every unique visitor ID grows linearly with cardinality and can consume gigabytes for hundreds of millions of unique elements.
  • PFADD/PFCOUNT trade exactness for bounded memory — ideal for 'unique daily visitors' or 'unique searches' metrics where an approximate count is acceptable.
Interviewer Takeaway: When an interviewer asks for 'unique count at massive scale' and exact precision isn't required, HyperLogLog is the memory-efficient answer over a Set.
Caching PatternsMust-Know

Q6: Explain the cache-aside pattern and its main weakness during a cold start or cache flush.

Executive Answer:In cache-aside, the application checks Redis first and falls back to the database on a miss, populating the cache afterward; its weakness is that a cold cache (or mass expiry) sends every request straight to the DB simultaneously.
Deep Dive Analysis:
  • This 'cache stampede' or 'thundering herd' scenario can take down an underprovisioned database that was only ever sized for cache-hit traffic.
  • Mitigations include per-key mutexes/locks during rebuild, staggered TTLs with jitter, and pre-warming the cache before a known traffic spike.
Interviewer Takeaway: Always pair cache-aside with a stampede-protection mechanism in a system design answer — mentioning the pattern alone isn't enough at the senior level.
Caching PatternsMust-Know

Q7: Compare write-through and write-behind caching in terms of consistency and failure risk.

Executive Answer:Write-through writes synchronously to both cache and DB before acknowledging, guaranteeing consistency at the cost of latency; write-behind acknowledges after the cache write and flushes to the DB asynchronously, risking data loss if the cache fails before the flush.
Deep Dive Analysis:
  • Write-through is preferred when correctness matters more than write latency (financial ledgers, inventory counts).
  • Write-behind is preferred for high write-volume, loss-tolerant data (metrics, view counts, activity logs) where batching dramatically reduces DB write pressure.
  • A hybrid approach batches write-behind flushes but also persists an intent log (e.g. via Streams) so a crashed cache node's pending writes can be replayed.
Interviewer Takeaway: Frame the choice as latency/throughput vs data-loss window — there is no universally 'correct' pattern, only the right trade-off for the data's importance.
Caching PatternsMedium

Q8: When would you choose read-through caching over application-managed cache-aside?

Executive Answer:Read-through pushes the cache-population logic into the caching layer itself (via a loader function), simplifying application code at the cost of coupling the cache library to the data-fetching logic.
Deep Dive Analysis:
  • Frameworks or caching proxies that support read-through remove repetitive 'check cache, else query DB, else populate' boilerplate from every service.
  • It's less flexible when different call sites need different TTLs, serialization formats, or fallback behavior for the same key.
Interviewer Takeaway: Read-through and cache-aside solve the same problem; the difference is purely where the population logic lives, not the underlying consistency guarantees.
Eviction PoliciesMust-Know

Q9: How does Redis's default maxmemory-policy of noeviction behave once memory is full, and why is that dangerous?

Executive Answer:With noeviction, once maxmemory is reached Redis rejects all further write commands with an OOM error while still allowing reads — this is dangerous because it silently breaks write paths in production if maxmemory wasn't sized correctly.
Deep Dive Analysis:
  • noeviction is the safe-by-default choice for Redis used as a system of record (not just a cache), where silently losing data via eviction would be worse than rejecting writes.
  • For a pure cache use case, this default should almost always be overridden to an active eviction policy so the application never sees OOM errors from a full cache.
Interviewer Takeaway: Always explicitly state your chosen maxmemory-policy in a system design answer — leaving it as the default is a common tell of shallow Redis knowledge.
Eviction PoliciesMedium

Q10: What is the difference between allkeys-lru and volatile-lru eviction policies?

Executive Answer:allkeys-lru can evict any key regardless of whether it has a TTL set; volatile-lru only considers keys that have an expiry set, leaving keys without a TTL untouched even under memory pressure.
Deep Dive Analysis:
  • volatile-lru is useful when a Redis instance mixes cache data (with TTLs) and persistent data (without TTLs, e.g. session tokens you never want auto-evicted) on the same instance.
  • If no keys have a TTL under a volatile-* policy, Redis behaves like noeviction and starts rejecting writes.
Interviewer Takeaway: Use volatile-* policies only when you deliberately mix evictable and non-evictable data in one instance; otherwise allkeys-* policies are simpler and safer.
Eviction PoliciesHard

Q11: How does Redis approximate LRU eviction without maintaining a true, fully-ordered LRU linked list?

Executive Answer:Redis samples a small random subset of keys (default 5, tunable via maxmemory-samples) and evicts the least-recently-used among that sample, avoiding the memory and CPU overhead of maintaining a globally accurate LRU list.
Deep Dive Analysis:
  • Increasing maxmemory-samples improves approximation accuracy at the cost of more CPU per eviction; Redis also maintains a small eviction pool to make repeated approximations converge closer to true LRU over time.
  • For most workloads, approximate LRU performs close enough to true LRU that the memory savings are worth the trade-off.
Interviewer Takeaway: Mentioning that Redis's LRU is 'approximated via sampling, not exact' is a strong signal of deeper internals knowledge in interviews.
Eviction PoliciesMedium

Q12: When would LFU (Least Frequently Used) eviction outperform LRU for a caching workload?

Executive Answer:LFU outperforms LRU when a small set of very hot keys are accessed constantly but interspersed with many one-off accesses to cold keys, since LRU would keep promoting those cold, recently-touched keys and evicting truly popular ones.
Deep Dive Analysis:
  • A classic example is a product catalog where a handful of best-sellers are read thousands of times per minute alongside long-tail products read once and never again — LRU can evict a best-seller simply because a cold item was accessed a moment later.
  • LFU tracks an approximate access-frequency counter per key (with probabilistic decay) so consistently popular keys survive longer.
Interviewer Takeaway: Choose LFU over LRU when 'access frequency' better predicts future access than 'access recency.'
PersistenceMust-Know

Q13: What happens during Redis's BGSAVE, and why doesn't it block client commands?

Executive Answer:BGSAVE forks a child process that shares the parent's memory pages via copy-on-write; the child writes a consistent snapshot to disk while the parent continues serving commands, only duplicating memory pages that are modified during the snapshot.
Deep Dive Analysis:
  • Because fork() is fast (page tables are copied, not the data itself), the parent process resumes serving requests almost immediately after the fork.
  • If write volume during the snapshot is very high, copy-on-write can cause significant extra memory usage, potentially doubling resident memory on a worst-case, all-keys-modified workload.
Interviewer Takeaway: RDB's non-blocking nature comes from OS-level copy-on-write forking, not from any special Redis-side buffering.
PersistenceHard

Q14: Compare the three AOF appendfsync options and their durability/performance trade-offs.

Executive Answer:always fsyncs on every write (safest, worst latency), everysec fsyncs once per second in a background thread (default, loses at most ~1 second of writes), and no leaves fsync timing to the OS (fastest, least durable, can lose much more on a crash).
Deep Dive Analysis:
  • everysec is the recommended default for most production workloads because it bounds data loss tightly while keeping throughput close to no-fsync performance.
  • always is typically reserved for financial or compliance-critical data where even a 1-second loss window is unacceptable, accepting the throughput hit.
Interviewer Takeaway: Frame AOF durability as a dial, not a binary — pick the fsync policy that matches the actual cost of losing N seconds of writes for that specific dataset.
PersistenceMedium

Q15: Why would a team choose hybrid RDB+AOF persistence instead of just one mechanism?

Executive Answer:Hybrid persistence prefixes AOF rewrites with an RDB-formatted snapshot, combining RDB's fast binary restart with AOF's minimal data-loss window from the log tail — giving both fast recovery and tight durability.
Deep Dive Analysis:
  • Loading a pure AOF file means replaying potentially millions of individual commands, which is far slower than loading one compact RDB snapshot.
  • Hybrid mode loads the RDB preamble instantly, then replays only the small tail of commands written since the last rewrite.
Interviewer Takeaway: Hybrid RDB+AOF (aof-use-rdb-preamble yes) is the practical default recommendation for any Redis instance acting as more than a disposable cache.
PersistenceMedium

Q16: What's the risk of enabling only RDB persistence with default snapshot intervals (e.g. save 900 1)?

Executive Answer:A crash right before a scheduled snapshot can lose up to the entire interval's worth of writes (e.g. up to 15 minutes with the default 900-second rule), which is unacceptable for anything beyond a pure, rebuildable cache.
Deep Dive Analysis:
  • Tuning tighter save intervals (e.g. save 60 1) reduces the loss window but increases fork frequency and associated CPU/memory overhead.
  • For any dataset where losing minutes of writes matters, AOF (or hybrid) is required alongside or instead of RDB alone.
Interviewer Takeaway: Always ask 'how many minutes of data loss is acceptable' before recommending RDB-only persistence in a design interview.
Replication & HAMust-Know

Q17: How does Redis Sentinel decide a primary is actually down before triggering failover?

Executive Answer:Each Sentinel independently marks a primary as 'subjectively down' (SDOWN) after failing to get a response within a configured timeout, then Sentinels gossip and only declare 'objectively down' (ODOWN) once a configured quorum of Sentinels agree.
Deep Dive Analysis:
  • This quorum requirement prevents a single Sentinel's network blip from triggering an unnecessary failover.
  • Once ODOWN is reached, Sentinels run a leader-election (using Raft-like majority voting) to pick one Sentinel to execute the failover, which promotes the most up-to-date replica (based on replication offset).
Interviewer Takeaway: Sentinel failover is a two-phase agreement: quorum to detect failure, then a separate leader election to execute the promotion — not a single Sentinel unilaterally deciding.
Replication & HAHard

Q18: In Redis Cluster, why are keys partitioned into exactly 16384 hash slots instead of using simple consistent hashing?

Executive Answer:A fixed slot count decouples 'which node owns which data' from 'how many nodes exist' — resharding means reassigning a range of slot numbers between nodes (a metadata change), not rehashing every key, and 16384 was chosen so the per-node slot bitmap stays small even at large cluster sizes.
Deep Dive Analysis:
  • Each node tracks slot ownership as a compact bitmap; with more slots (say millions), that bitmap and its gossip-protocol propagation overhead would grow too large.
  • Clients cache a slot-to-node mapping and only need to update it on MOVED errors, avoiding a full rehash of the keyspace during scaling events.
Interviewer Takeaway: Redis Cluster's hash slots are a deliberately fixed, coarse-grained partitioning scheme optimized for cheap resharding metadata, not maximal hash distribution precision.
Replication & HAMedium

Q19: What causes a CROSSSLOT error in Redis Cluster, and how do you avoid it for multi-key operations?

Executive Answer:A CROSSSLOT error occurs when a single command touches multiple keys that hash to different slots (potentially living on different nodes); it's avoided by using hash tags (curly braces around the part of the key used for hashing) to force related keys into the same slot.
Deep Dive Analysis:
  • For example, {order:5001}:items and {order:5001}:status both hash only on 'order:5001', guaranteeing they land in the same slot and can be used together in MGET, transactions, or Lua scripts.
  • This is a deliberate design trade-off: Cluster sacrifices arbitrary multi-key atomicity for horizontal scalability.
Interviewer Takeaway: Whenever multi-key atomic operations are required in Cluster mode, design your key naming scheme around hash tags up front.
Replication & HAHard

Q20: Why is asynchronous replication in Redis considered an AP-leaning trade-off rather than strongly consistent?

Executive Answer:Because the primary acknowledges a write to the client before confirming the replica has received it, a primary failure can lose the last few writes that hadn't yet propagated, and a promoted replica becomes the new source of truth without those writes.
Deep Dive Analysis:
  • The WAIT command can force the primary to block until N replicas acknowledge a write, trading availability/latency for stronger durability guarantees on a per-command basis.
  • Even with WAIT, Redis replication is not fully synchronous/linearizable by default — it's an opt-in tool for specific critical writes, not the default behavior.
Interviewer Takeaway: State explicitly that Redis defaults to eventual consistency between primary and replicas, and that WAIT is the escape hatch for stronger guarantees on specific operations.
Replication & HAHard

Q21: How would you size and design Redis Cluster nodes for a 50 million session, multi-region user base?

Executive Answer:Estimate total memory (sessions x average size x replication factor), pick a shard count that keeps each primary's dataset comfortably under a few GB for fast BGSAVE/failover, and add at least one replica per shard for read scaling and failover, ideally in the same region as the primary for lower replication lag.
Deep Dive Analysis:
  • For example, 50M sessions x 2KB average x 2 (primary+replica) is roughly 200GB total memory — divided across, say, 20 shards of ~10GB each keeps snapshot and failover times manageable.
  • For multi-region access, consider active-active patterns (CRDB-based Redis Enterprise or application-level regional sharding) since native OSS Cluster replication is single-region-primary by design.
Interviewer Takeaway: Always work capacity numbers backward from acceptable failover/snapshot time per shard, not just total memory divided evenly.
Distributed LocksMust-Know

Q22: What problem does the Redlock algorithm solve, and what is its core mechanism?

Executive Answer:Redlock provides a distributed mutual-exclusion lock resilient to a single Redis instance failing, by requiring a client to acquire the same lock key on a majority of N independent Redis masters within a bounded time window.
Deep Dive Analysis:
  • Each acquisition attempt uses SET key value NX PX <ttl> on every instance; the lock is considered held only if a majority (e.g. 3 of 5) respond OK before a computed time budget expires.
  • Release uses a Lua script that checks the stored value matches the client's unique token before deleting, so a client never releases a lock it doesn't currently own (e.g. after its TTL already expired and was re-acquired by someone else).
Interviewer Takeaway: Redlock's safety comes from majority quorum across independent failure domains, not from any single instance being 'more reliable.'
Distributed LocksHard

Q23: What is the main criticism of Redlock, and how do fencing tokens address it?

Executive Answer:Martin Kleppmann's critique is that Redlock assumes bounded clock drift and process pauses, but GC pauses, VM suspensions, or NTP clock jumps can cause a client to believe it still holds a lock after its TTL has actually expired elsewhere; fencing tokens (a monotonically increasing number issued with each lock) let the protected resource itself reject stale operations.
Deep Dive Analysis:
  • Without fencing, a paused client can 'wake up' after its lock expired, still believe it holds the lock, and write to the protected resource concurrently with the new lock holder.
  • With fencing, the protected resource (e.g. a storage service) rejects any write carrying a fencing token lower than the highest it has already seen, making the lock safe even if two clients briefly both think they hold it.
Interviewer Takeaway: Redlock alone provides liveness/availability guarantees, not perfect safety under adversarial timing — pair it with fencing tokens whenever correctness truly cannot tolerate a rare double-acquire.
Distributed LocksMedium

Q24: Why should a single-instance Redis lock (SET NX PX) be considered insufficient for critical distributed coordination?

Executive Answer:A single-instance lock has a single point of failure: if that Redis instance crashes after granting the lock but before the client releases it (and before replication catches up, if using a replica), a failover can promote a replica that never saw the lock, allowing a second client to acquire it concurrently.
Deep Dive Analysis:
  • This is precisely the scenario Redlock's multi-instance majority quorum is designed to reduce the probability of, though not eliminate entirely under worst-case timing.
  • For many practical use cases (e.g. deduplicating a background job within one datacenter), a single-instance lock with a reasonable TTL and idempotent downstream operations is an acceptable, simpler trade-off.
Interviewer Takeaway: Match lock robustness to actual business risk — not every use of a lock needs full Redlock; idempotency downstream is often the more practical safety net.
Rate LimitingHard

Q25: How would you implement a sliding-window rate limiter using a Redis Sorted Set?

Executive Answer:Store each request's timestamp as both the score and a unique member in a ZSET per client key; on each request, remove entries older than the window (ZREMRANGEBYSCORE), count remaining entries (ZCARD), and allow the request only if the count is under the limit, then ZADD the new timestamp.
Deep Dive Analysis:
  • This gives a true sliding window (not a fixed-bucket approximation), smoothing out the burst-at-boundary problem where a fixed window allows 2x the limit right at the window edge.
  • Wrap the remove+count+add sequence in a Lua script or MULTI/EXEC to keep it atomic across concurrent requests for the same client.
Interviewer Takeaway: A ZSET-based sliding-window log is the go-to answer whenever an interviewer pushes back on 'fixed window rate limiting allows bursts at the boundary.'
Rate LimitingMedium

Q26: Compare token bucket and fixed-window counter approaches for Redis-based rate limiting.

Executive Answer:A fixed-window counter (INCR + EXPIRE) is simple and cheap but allows up to 2x the limit in requests clustered around a window boundary; a token bucket (tracked via a String holding token count plus last-refill timestamp) allows controlled bursts up to the bucket size while enforcing a steady average refill rate.
Deep Dive Analysis:
  • Fixed-window is O(1) per request and trivial to implement, making it a reasonable default when exact burst control isn't critical.
  • Token bucket requires a small Lua script to atomically compute elapsed time, refill tokens, and decrement on each request, but better models real-world 'allow bursts, then throttle' traffic shaping needs.
Interviewer Takeaway: Pick fixed-window for simplicity when burst tolerance at boundaries is acceptable; pick token bucket when you need to explicitly control burst size independent of the average rate.
Redis FundamentalsMedium

Q27: Why are Redis transactions (MULTI/EXEC) not equivalent to full ACID database transactions?

Executive Answer:MULTI/EXEC queues commands and executes them atomically as a batch with no other client's commands interleaved, but it provides no rollback on a runtime error within the batch — if one queued command fails, the others still execute.
Deep Dive Analysis:
  • Only syntax errors detected at queue time abort the whole transaction; a runtime error (e.g. wrong type operation) on one command simply fails that command while the rest proceed.
  • For true conditional atomicity (check-then-act across multiple keys), WATCH provides optimistic locking, aborting EXEC if a watched key changed since WATCH was called.
Interviewer Takeaway: Redis transactions guarantee isolation (no interleaving) and atomarity of execution as a batch, but not automatic rollback — use WATCH for optimistic concurrency control and Lua scripts when you need true all-or-nothing semantics with logic.
Redis FundamentalsMust-Know

Q28: Why is Redis effectively single-threaded for command execution, and how does that affect design decisions?

Executive Answer:A single event-loop thread executes commands one at a time, which eliminates the need for internal locking on data structures and guarantees every command is atomic by construction, but also means one slow command (e.g. KEYS * or a huge SORT) blocks every other client until it completes.
Deep Dive Analysis:
  • Since Redis 6, I/O threading was added to parallelize reading/parsing client input and writing output, but command execution itself remains single-threaded.
  • This is why SCAN (cursor-based, incremental) replaces KEYS (blocking, O(N) full scan) as the production-safe way to iterate a large keyspace.
Interviewer Takeaway: Every Redis command choice should be evaluated for 'could this block the single execution thread for a noticeable amount of time' — that's the core operational risk model for Redis.
Caching PatternsHard

Q29: What is the N+1 cache invalidation problem, and how do you handle invalidating a cache entry that depends on multiple upstream tables?

Executive Answer:When a cached value is derived from joining multiple tables, a write to any contributing table can silently leave the cache stale unless every write path explicitly knows to invalidate that derived key; the common fix is tagging cache keys with the source entity IDs they depend on and invalidating by tag, or simply keeping TTLs short enough that staleness is bounded and acceptable.
Deep Dive Analysis:
  • Explicit invalidation (pub/sub 'entity changed' events triggering targeted DEL calls) gives fresher data but adds coupling between every writer and the cache layer.
  • A pattern used at scale is publishing domain change events (via Streams or a message bus) that a dedicated cache-invalidation consumer subscribes to, decoupling writers from cache-invalidation logic.
Interviewer Takeaway: For derived/joined cached data, prefer event-driven invalidation or short TTLs over trying to enumerate every write path that could affect the cached value.
Caching PatternsMedium

Q30: How do you decide the right TTL for a cached value in a system design interview?

Executive Answer:Balance the cost of a cache miss (DB load, latency) against the cost of staleness (how quickly the underlying data actually changes and how much staleness the business can tolerate); rapidly changing data gets short TTLs (seconds), rarely changing reference data gets long TTLs (hours to days).
Deep Dive Analysis:
  • Adding jitter to any TTL avoids mass simultaneous expiry (cache stampede) for keys written in bulk at the same time.
  • For data that must never be stale beyond a hard bound (e.g. account balance shown at checkout), prefer explicit invalidation on write over relying on TTL alone.
Interviewer Takeaway: Always justify a TTL value with a concrete business reason ('stock count can be 5 seconds stale during checkout') rather than picking an arbitrary round number.
Common Mistakes

Mistakes That Sink Otherwise Strong Candidates

Leaving maxmemory-policy at its default (noeviction) on an instance used purely as a cache.

Why it happens: Teams provision Redis for caching without revisiting the default configuration, assuming Redis will 'just evict old stuff' automatically once memory fills up.

The fix: Explicitly set an eviction policy like allkeys-lru or allkeys-lfu for pure cache instances, reserving noeviction only for Redis deployments acting as a system of record.

Running the KEYS * command (or unbounded pattern scans) against a production instance.

Why it happens: KEYS is the first command developers learn for inspecting a keyspace, and it works fine on a small local dataset, masking its O(N) blocking behavior until the dataset grows in production.

The fix: Use SCAN with a cursor for any production keyspace iteration — it processes the keyspace incrementally without blocking other clients.

Treating Redlock as an unconditionally safe distributed lock for any critical section.

Why it happens: Redlock's design looks like a rigorous consensus algorithm, so teams assume it eliminates all race conditions without accounting for clock drift or process pauses.

The fix: Use Redlock for reducing the probability of concurrent access in practice, and add fencing tokens on the protected resource itself whenever correctness truly cannot tolerate a rare double-acquisition.

Not adding jitter to cache TTLs, causing thousands of keys to expire at the same instant.

Why it happens: A batch cache-warming job or bulk cache population at startup writes many keys with the exact same TTL value, so they all expire simultaneously later.

The fix: Add a randomized offset (e.g. +/- 10-15% of the base TTL) to every cache write so expirations spread out over time instead of clustering.

Storing large multi-megabyte blobs as single String values on a hot key.

Why it happens: It's the path of least resistance to just JSON.stringify() an entire nested object and cache it as one value.

The fix: Break large objects into Hashes with smaller fields, compress payloads, or store only the frequently-accessed subset in Redis while keeping the full object in the primary datastore.

Assuming replica reads are always up to date immediately after a write to the primary.

Why it happens: Redis replication feels instantaneous in local development with negligible network latency, hiding the asynchronous replication lag that appears under real production load.

The fix: Read from the primary for any read-after-write consistency requirement, or use WAIT to confirm replica acknowledgment before returning success for critical writes.

Designing multi-key operations in Redis Cluster without considering hash slot placement.

Why it happens: Single-node Redis development never surfaces CROSSSLOT errors, so the issue only appears after deploying to a real Cluster topology.

The fix: Use hash tags ({entityId}:field) from the start of key-schema design for any keys that will ever need to be operated on together.

Enabling AOF with appendfsync always without load-testing the latency impact.

Why it happens: Teams pick the 'safest sounding' option without benchmarking, assuming Redis's in-memory speed will absorb the fsync cost.

The fix: Benchmark appendfsync everysec first (the recommended default) and only move to always for the specific keys/use cases where a 1-second loss window is genuinely unacceptable.

Cheat Sheet

Quick-Reference Cheat Sheet

Data Structure Complexity
String GET / SETO(1)
Hash HGET / HSET / HDELO(1)
Sorted Set ZADD / ZRANGE / ZRANKO(log N)
List LPUSH / RPUSHO(1)
List LINDEX / LREM (middle access)O(N)
Set SADD / SISMEMBERO(1)
Stream XADD (append)O(1) amortized
HyperLogLog PFADD / PFCOUNTO(1) / ~12KB fixed memory
Eviction Policy Comparison
noeviction (default)Rejects writes once maxmemory hit; safest for data-of-record
allkeys-lruEvicts least-recently-used across all keys, approximated via sampling
allkeys-lfuEvicts least-frequently-used; best for hot/cold access skew
volatile-ttlEvicts keys with the nearest expiry first
volatile-lru / volatile-lfuLRU/LFU eviction limited to keys that have a TTL set
allkeys-random / volatile-randomEvicts a random key; cheapest, least predictable
RDB vs AOF Persistence Trade-offs
RDB restart speedFast (single binary snapshot load)
RDB data-loss windowUp to the snapshot interval (minutes)
AOF (everysec) data-loss windowAt most ~1 second
AOF (always) data-loss window~0, but highest write latency
AOF restart speedSlower (replays the command log)
Hybrid RDB+AOFFast restart + minimal loss window (recommended default)
Caching Pattern Quick Reference
Cache-AsideApp manages reads/writes; simplest, risk of stampede on miss
Write-ThroughSynchronous write to cache + DB; strong consistency, higher latency
Write-BehindAsync batched DB flush; lowest latency, risk of loss on cache crash
Read-ThroughCache layer owns population logic via a loader function
Replication, Cluster & HA
Replication modeAsynchronous by default (AP-leaning)
WAIT commandBlocks for N replica acknowledgments on demand
Sentinel quorumMajority agreement required before ODOWN + failover
Cluster hash slotsFixed at 16384, assigned via CRC16(key) mod 16384
CROSSSLOT fixUse hash tags {key}:suffix to co-locate related keys
Locks & Rate Limiting
Basic distributed lockSET key token NX PX <ttl>
Safe lock releaseLua script: GET check token match before DEL
Redlock quorumMajority (N/2 + 1) of independent Redis masters
Fixed-window rate limitINCR + EXPIRE per time bucket
Sliding-window rate limitZSET timestamps + ZREMRANGEBYSCORE + ZCARD
Token bucket rate limitLua script tracking token count + last refill time
Assessment Integration

Recommended Practice Quizzes on QuizCluster

Test your retention and prepare for timed live coding and MCQ technical screening rounds:

Frequently Asked Questions

Is Redis a database or just a cache?

Both, depending on configuration. With persistence disabled, Redis is commonly used as a pure cache in front of a source-of-truth database. With RDB/AOF persistence, replication, and Cluster enabled, Redis is frequently used as a primary data store for use cases like session storage, leaderboards, and real-time counters.

Can Redlock guarantee perfect mutual exclusion in all failure scenarios?

No. Redlock provides strong practical guarantees under normal operating conditions and node failures, but under extreme clock drift or long process pauses (GC, VM suspension), it cannot guarantee perfect safety. Pair it with fencing tokens on the protected resource if correctness must hold even in those edge cases.

How do you scale Redis beyond what a single node's memory can hold?

Use Redis Cluster to shard data across multiple primary nodes via hash slots, each with its own replicas for high availability. Design keys with hash tags for any operations that need multiple keys to co-locate on the same shard.

When should I choose Redis over Memcached for caching?

Choose Redis when you need richer data structures (Sorted Sets, Hashes, Streams), persistence, replication/HA, pub/sub, or built-in support for patterns like distributed locks and rate limiting. Choose Memcached for the simplest possible pure key-value cache with a slightly lower per-operation memory overhead at very high scale.

Explore Other Preparation Guides

Software Engineering
How to Prepare for SDE Interview: Complete 2026 Roadmap
16 min readRead →
Java Ecosystem
How to Prepare for Java Developer Interview: Core to Spring Boot & JVM
18 min readRead →
Microservices & Distributed Systems
How to Prepare for Microservices Developer Interview: Distributed Architecture & Cloud
17 min readRead →
System Design
System Design Interview Guide: Complete 2026 Roadmap
21 min readRead →
Databases
SQL Interview Questions & Preparation Guide: Beginner to Advanced
17 min readRead →
Programming Languages
Python Interview Preparation: Complete Guide for 2026
17 min readRead →
Frontend Engineering
React Interview Preparation: React 19 & Next.js Guide
17 min readRead →
Cloud & DevOps
Kubernetes Interview Guide: Architecture, Pods, Networking & Troubleshooting
17 min readRead →
Cloud & DevOps
AWS Solutions Architect Interview Guide: Real Architecture Scenarios
17 min readRead →
Databases
Database System Design: SQL vs NoSQL, Sharding, Replication & Indexing
19 min readRead →
Microservices & Distributed Systems
Kafka Interview Guide: Architecture, Consumers, Partitions & Exactly-Once Semantics
17 min readRead →
Backend Engineering
REST API Design Interview Guide: Authentication, Pagination, Versioning & Rate Limiting
15 min readRead →
Cloud & DevOps
Docker Interview Guide: Images, Containers, Networking & Production Debugging
15 min readRead →
Programming Languages
JavaScript & TypeScript Interview Guide: From Closures to the Event Loop
17 min readRead →
Backend Engineering
Node.js Backend Interview Guide: Event Loop, Streams, APIs & Scaling
17 min readRead →
Software Engineering
Concurrency Interview Guide: Threads, Locks, Race Conditions & Deadlocks
17 min readRead →
Software Engineering
Dynamic Programming Patterns: How to Recognize and Solve DP Problems
17 min readRead →