MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Redis Caching
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

Redis Caching

Reading45 min

Redis shows up in nearly every backend system design interview as "put a cache in front of the database." The follow-up questions, invalidation, stampedes, eviction, are where most candidates fall apart. This lesson covers the data structures that actually matter, a real cache-aside implementation, a Redis-backed rate limiter, and what happens when Redis itself runs out of memory.

Redis data structures and when to use each

Type Use it for
String A simple cached value, a counter (INCR), a feature flag
Hash Object-like data, a user profile, where you want to read or update one field without touching the rest
List A queue, or a capped recent-activity feed (LPUSH plus LTRIM)
Set Unique membership checks: "has this user already done X"
Sorted Set (ZSET) Anything ranked by a number: leaderboards, rate-limit windows
Stream An append-only event log with consumer groups, a lightweight Kafka
Python
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)

r.set("user:42:name", "Ada", ex=300)                        # string, expires in 300s
r.hset("user:42", mapping={"name": "Ada", "plan": "pro"})   # hash: update one field, leave the rest
r.zadd("leaderboard", {"user:42": 1500})                    # sorted set: O(log n) insert, ranked reads
r.zrevrange("leaderboard", 0, 9, withscores=True)           # top 10

Remember: pick the Redis type that matches the access pattern you need, not just "can this data fit in a string." A leaderboard is a sorted set because you need ranked reads, not just storage.

Sign in to try this knowledge check.

Cache-aside: the default pattern

The application checks the cache first, falls back to the source of truth on a miss, and fills the cache for next time.

Python
CACHE_TTL_SECONDS = 300

def get_user(user_id: int, db) -> dict:
    cache_key = f"user:{user_id}"
    cached = r.get(cache_key)
    if cached is not None:
        return json.loads(cached)                      # hit — no DB round trip

    user = db.query_one("SELECT id, name, email FROM users WHERE id = %s", [user_id])
    if user is None:
        return None
    r.set(cache_key, json.dumps(user), ex=CACHE_TTL_SECONDS)
    return user

def update_user(user_id: int, fields: dict, db) -> None:
    db.execute("UPDATE users SET name = %s WHERE id = %s", [fields["name"], user_id])
    r.delete(f"user:{user_id}")                          # invalidate — don't rewrite in place

Why delete on write, instead of updating the cache in place? Updating the cache to match a write means every single write path must remember to keep the cache in sync. One forgotten spot leaves stale data forever. Deleting is simpler and self-healing: the very next read repopulates the cache from the real source of truth.

Cache stampede is the other classic failure. If one hot key expires and a thousand requests all miss at the same instant, all thousand hit the database at once to refill it. Mitigate with a short lock around the refill, jittered TTLs so keys don't all expire in the same second, or serving the stale value while one request refreshes it in the background.

Remember: on write, delete the cache key, don't overwrite it. The next read repopulates from the real source of truth, which is simpler than keeping two copies in sync forever.

Sign in to try this knowledge check.

Eviction policies: what happens when Redis runs out of memory

Once Redis hits its configured maxmemory, it has to free space for a new write. Which key it throws away is the eviction policy.

Policy Behavior
noeviction Reject the write with an error instead of evicting anything
allkeys-lru / allkeys-lfu Evict least-recently / least-frequently used, across every key
volatile-lru / volatile-lfu / volatile-ttl Same idea, but only considers keys that already have a TTL set
allkeys-random Evict a random key

The choice depends on what Redis is holding. If Redis is a pure cache, everything in it is disposable and can be rebuilt from the database, so an allkeys-* policy is safe. If Redis mixes disposable cache data with data you actually need to keep, like session state or queue contents, use a volatile-* policy instead: only the keys you deliberately gave a TTL become eligible for eviction, and anything without one is never silently dropped under memory pressure.

Remember: if Redis only holds a cache, allkeys-* is safe. If it also holds data you can't afford to lose, use volatile-* so only your TTL'd cache keys are ever evicted.

Sign in to try this knowledge check.

A distributed lock, and its real problems

SET key value NX PX ttl sets a key only if it doesn't already exist (NX), with an expiry in milliseconds (PX) so a crashed holder doesn't lock everyone out forever.

Python
import uuid

def acquire_lock(r: redis.Redis, lock_name: str, ttl_ms: int = 5000) -> str | None:
    token = str(uuid.uuid4())                            # unique per attempt, needed to release safely
    acquired = r.set(f"lock:{lock_name}", token, nx=True, px=ttl_ms)
    return token if acquired else None

# Release must be one atomic check-and-delete — a plain GET then DEL from Python has a race window
RELEASE_LOCK_SCRIPT = """
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end
"""

def release_lock(r: redis.Redis, lock_name: str, token: str) -> bool:
    return r.eval(RELEASE_LOCK_SCRIPT, 1, f"lock:{lock_name}", token) == 1

Here's why the token matters: without it, process A acquires the lock, runs longer than the TTL, and the lock expires while A is still working. Process B then acquires it. When A finally finishes, a plain DEL would release a lock A no longer owns, letting a third process C grab it while B still believes it's the only holder. Checking the token before deleting closes that window.

What interviewers actually want you to say: a single Redis instance's lock is not safe across a failover. If the primary crashes right after granting a lock, before replicating it to a replica, and that replica gets promoted, a second client can acquire the "same" lock, because the new primary never saw it. Treat this as a best-effort optimization, not a correctness guarantee, unless you specifically implement and understand a multi-instance quorum protocol like Redlock.

Remember: release a lock with a token-checked script, never a plain DEL. A single Redis instance's lock is best-effort, not safe across a failover.

Sign in to try this knowledge check.

A sliding-window rate limiter

A fixed-window counter (INCR plus EXPIRE) is cheap but allows a burst of up to twice the limit across a window boundary: once right before the window resets, once right after.

Python
def is_rate_limited_sliding(r: redis.Redis, user_id: int, limit: int = 100, window_seconds: int = 60) -> bool:
    key = f"ratelimit:sliding:{user_id}"
    now = time.time()
    pipe = r.pipeline()
    pipe.zremrangebyscore(key, 0, now - window_seconds)   # drop entries older than the window
    pipe.zadd(key, {str(uuid.uuid4()): now})               # record this request
    pipe.zcard(key)                                         # count requests in the window
    pipe.expire(key, window_seconds)
    _, _, count, _ = pipe.execute()
    return count > limit

r.pipeline() batches these four commands into a single round trip. That's worth naming as a general Redis technique beyond rate limiting: fewer round trips, and Redis runs a pipeline's commands without another client's commands interleaved in between, though it is not a single atomic step the way a Lua script is. For true atomicity under heavy concurrent access to the same key, move this logic into a Redis Lua script so the whole read-check-write happens as one atomic step on the server.

Remember: a fixed-window counter allows a 2x burst at the window boundary. A sorted set that prunes old entries before counting fixes that at the cost of more memory per key.

Sign in to try this knowledge check.
PreviousPractice Test: DatabasesNextRedis Advanced Patterns

Course progress

0%
0 of 177 modules complete

On this page

  • Redis data structures and when to use each
  • Cache-aside: the default pattern
  • Eviction policies: what happens when Redis runs out of memory
  • A distributed lock, and its real problems
  • A sliding-window rate limiter