Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›System Design›Caching Strategies — CDN, Redis, Memcached

Fundamentals

Caching Strategies — CDN, Redis, Memcached

Caching is the practice of storing frequently accessed data in a high-speed memory layer to bypass expensive disk or network operations. By reducing latency and offloading primary databases, caching allows systems to handle significant traffic spikes with consistent performance. You should reach for caching whenever your system bottlenecks at the database layer or when read-heavy workloads cause unacceptable user-facing latency.

The Core Concept: Spatial and Temporal Locality

At the heart of caching lies the principle of locality: if you access a piece of data once, you are statistically likely to access it again soon (temporal locality), and if you access one piece of data, you are likely to access nearby data (spatial locality). A cache works by intercepting a request before it reaches the origin server. When a request arrives, the system checks the cache; if the key exists, it returns the value (a cache hit), which is orders of magnitude faster than a database query. If the key is missing (a cache miss), the system fetches data from the persistent store and populates the cache for future requests. Understanding this flow is vital because every cache adds complexity regarding data consistency; you must decide how long a piece of data should 'live' in memory before it is considered stale, a concept known as Time-to-Live (TTL).

# Simple dictionary-based cache simulation
cache = {}

def get_data(key, fetch_func):
    if key in cache:
        return cache[key] # Return hit immediately
    value = fetch_func(key) # Fetch from origin
    cache[key] = value # Populate for next time
    return value

CDN: Edge Caching for Static Assets

Content Delivery Networks (CDNs) act as the first line of defense, sitting at the 'edge' of the internet, geographically closer to the end-user than your central server. CDNs are optimized for static assets like images, stylesheets, and scripts. By caching these assets globally, a user in Tokyo fetches their content from a nearby Japanese edge node rather than crossing the ocean to your primary server in California. This drastically reduces round-trip time (RTT). The logic here is that static content rarely changes; thus, we can set long expiration times. CDNs use a distributed architecture to minimize network latency. When considering a CDN, think about your traffic distribution: if your users are global, a CDN is mandatory to ensure uniform performance. You must manage cache invalidation carefully; if you update a global file, you need a mechanism to purge the edge nodes so users don't see outdated versions.

# Simulate a CDN cache hit vs miss scenario
edge_nodes = {'us-east': {}, 'eu-west': {}}

def serve_asset(node, asset_url):
    if asset_url in edge_nodes[node]:
        return "Serving from Edge: " + edge_nodes[node][asset_url]
    # Simulate fetching from origin
    data = "Global File Content"
    edge_nodes[node][asset_url] = data
    return "Serving from Origin: " + data

Memcached: Distributed Memory Object Caching

Memcached is a high-performance, distributed memory object caching system designed for simplicity. It is an in-memory key-value store that excels in scenarios where you need to cache the results of expensive database queries or API calls. Unlike a database, Memcached does not provide persistent storage; if the server restarts, the data is gone. Its strength lies in its multi-threaded architecture, allowing it to scale horizontally by adding more nodes. Because it is distributed, your client application must be 'cache-aware'—typically using consistent hashing to determine which specific Memcached node should store a given key. Use Memcached when you have a simple key-value workload that requires extremely low latency and high concurrency, but do not need advanced data structures or data persistence features beyond simple expiration logic.

import hashlib

class MemcachedCluster:
    def __init__(self, nodes):
        self.nodes = nodes # List of server addresses

    def get_node(self, key):
        # Consistent hashing logic to route key to node
        h = int(hashlib.md5(key.encode()).hexdigest(), 16)
        return self.nodes[h % len(self.nodes)]

# Node lookup for distributed caching

Redis: Advanced Data Structures and Persistence

Redis, or Remote Dictionary Server, is significantly more powerful than Memcached. While both act as in-memory stores, Redis supports complex data structures such as lists, sets, sorted sets, and hashes, allowing you to perform operations directly in memory that would otherwise require pulling the whole object back to the application. For example, using a sorted set in Redis, you can implement a leaderboard feature by storing user scores and ranking them entirely within the cache layer. Redis also offers persistence, allowing it to take snapshots of the data or write updates to an append-only file, ensuring that your cache does not lose its state during a reboot. Because of this persistence and the ability to perform atomic operations on data structures, Redis is often used not just as a cache, but as a secondary primary data store for transient data like session management or real-time counters.

# Redis-style sorted set operation
redis_cache = {'leaderboard': [('user_a', 50), ('user_b', 120)]}

def update_score(user, score):
    # Sort the list after adding an element
    redis_cache['leaderboard'].append((user, score))
    redis_cache['leaderboard'].sort(key=lambda x: x[1], reverse=True)
    return redis_cache['leaderboard']

Cache Eviction and Consistency Policies

Since cache memory is finite, you must decide what happens when the cache fills up. This is the 'eviction policy.' The most common strategy is Least Recently Used (LRU), which discards the item that has not been accessed for the longest time, assuming that older items are less relevant. Other strategies include First-In-First-Out (FIFO) or Least Frequently Used (LFU). Beyond eviction, you must handle the 'write-through' versus 'write-back' dilemma. In a write-through cache, the application writes to the cache and the database simultaneously, ensuring consistency but adding latency. In write-back, the application writes only to the cache, and the cache updates the database asynchronously. Write-back is faster but carries the risk of data loss if the cache server fails before syncing. Choose these policies based on your tolerance for stale data versus your requirement for write performance.

from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity):
        self.cache = OrderedDict()
        self.capacity = capacity

    def put(self, key, value):
        if key in self.cache: self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            self.cache.popitem(last=False) # Evict oldest

Key points

  • Caching utilizes the principles of temporal and spatial locality to reduce system latency.
  • CDNs are designed to cache static assets at the network edge to minimize global round-trip times.
  • Memcached provides a simple, high-speed, distributed key-value store optimized for horizontal scaling.
  • Redis differentiates itself by supporting advanced data structures and persistent storage options.
  • Cache hit ratios must be monitored closely to ensure that the memory overhead provides tangible performance gains.
  • Eviction policies like LRU are critical for managing memory constraints when dealing with finite cache sizes.
  • Choosing between write-through and write-back strategies depends on your system's tolerance for eventual consistency.
  • Consistent hashing is a fundamental technique used to distribute keys across a cluster of caching nodes.

Common mistakes

  • Mistake: Treating Redis as a primary database. Why it's wrong: Redis is an in-memory data store; if the node restarts and persistence isn't configured correctly, data is lost. Fix: Use it as a cache layer for frequently accessed data and rely on a persistent relational database as the source of truth.
  • Mistake: Using CDN for dynamic, user-specific content. Why it's wrong: CDNs are designed to cache static assets; attempting to cache personalized session data leads to security leaks and data inconsistency. Fix: Reserve CDN usage for static files and keep dynamic API calls handled by the origin server.
  • Mistake: Relying on Memcached for complex data structures. Why it's wrong: Memcached only stores simple key-value strings. Fix: Use Redis when you need rich data types like lists, sets, hashes, or sorted sets to perform server-side calculations.
  • Mistake: Ignoring cache invalidation policies. Why it's wrong: Stale data becomes a major issue if updates aren't propagated. Fix: Implement TTL (Time-to-Live) settings and choose between Write-Through, Write-Back, or Cache-Aside patterns based on consistency requirements.
  • Mistake: Setting the same TTL for all cache items. Why it's wrong: Items with different change frequencies require different expiration strategies to maintain efficiency. Fix: Use granular TTLs based on the business logic of each data type to minimize cache misses and data staleness.

Interview questions

What is the fundamental purpose of implementing a caching layer in a system architecture?

The fundamental purpose of a caching layer is to improve system performance and scalability by serving frequently accessed data from high-speed memory rather than fetching it from a slower persistent storage layer like a database. By reducing the number of expensive I/O operations and computations, caching lowers latency for end-users and significantly reduces the load on backend database servers. This allows a system to handle higher concurrency and throughput. For example, if a user requests a static profile page, fetching it from RAM takes sub-millisecond time, whereas hitting a disk-based database could take tens or hundreds of milliseconds depending on the complexity of the query and current load.

What is a Content Delivery Network (CDN) and how does it optimize content delivery for global users?

A CDN is a geographically distributed network of proxy servers designed to deliver content quickly by caching it as close to the end-user as possible. When a user requests a resource like an image or CSS file, the request is routed to the nearest edge server rather than the origin server. If the edge server has the file, it serves it immediately. If not, it fetches it from the origin and caches it for future requests. This drastically reduces round-trip time, known as latency, because the physical distance packets travel is minimized. It also protects the origin server by absorbing traffic spikes that would otherwise overwhelm a centralized data center.

Compare Redis and Memcached. When would you choose one over the other for your system?

Memcached is a simple, multi-threaded, in-memory key-value store optimized for raw speed and simplicity. It is excellent for caching simple strings or objects where you don't need complex data structures or persistence. Conversely, Redis is a more feature-rich, single-threaded data structure server. Redis supports advanced types like lists, sets, sorted sets, and hashes, and offers optional persistence, replication, and clustering. You should choose Memcached if your architecture strictly requires a lightweight, partitioned cache and you want to leverage multi-threading for high-throughput, simple operations. You should choose Redis if your use case requires persistence to disk, complex data manipulation, atomic operations on structures, or high-availability features like Sentinel or native replication, which make it more versatile for complex system design requirements.

Explain the Cache-Aside pattern. How does it handle data consistency between the database and the cache?

In the Cache-Aside pattern, the application code is responsible for managing the cache. When a request comes in, the application first checks the cache. If a cache miss occurs, the application queries the database, writes the result to the cache, and then returns the data. When updating data, the application updates the database first, then invalidates the corresponding entry in the cache. This pattern is robust because the cache is only populated on demand, which avoids filling it with data that is never accessed. However, the system must carefully handle potential race conditions where a concurrent read might write stale data back into the cache after an invalidation occurs, which is often mitigated by implementing a short Time-To-Live (TTL) on cache keys.

What is 'Cache Stampede' and how can you design your system to prevent it?

A cache stampede, also known as the thundering herd problem, occurs when a highly popular cache key expires or is evicted, causing a large volume of concurrent requests to experience a miss simultaneously. All these requests then proceed to hit the backend database at once, potentially causing a crash. To prevent this, you can implement 'probabilistic early expiration' or 'locking.' With locking, only the first thread that detects a miss is allowed to refresh the cache, while others wait or return stale data. Another strategy is to keep popular keys in the cache indefinitely and update them asynchronously before they expire, ensuring that the database is never hit by a sudden burst of identical requests.

How would you design a write-through caching strategy for a high-write-volume system, and what are the trade-offs?

In a write-through strategy, the application writes data to the cache and the database synchronously as a single atomic operation. The write is only considered complete once both stores are updated. The primary advantage is high data consistency; the cache is never stale relative to the database. However, this increases write latency because every write operation is bound by the speed of the slower persistent storage. For a system with massive write volume, this can lead to performance bottlenecks. To optimize this, one might consider asynchronous 'write-behind' (or write-back), where the cache is updated first, and the database update is queued for a later time, trading immediate consistency for significantly improved system throughput and write performance.

All System Design interview questions →

Check yourself

1. When implementing a 'Cache-Aside' pattern, what happens during a cache miss?

  • A.The application fetches data from the database and updates the cache.
  • B.The cache automatically pulls the latest version from the database.
  • C.The database pushes the data directly to the cache.
  • D.The application returns a 404 error to the user.
Show answer

A. The application fetches data from the database and updates the cache.
In Cache-Aside, the application is responsible for the interaction. If a miss occurs, the app fetches from the database and writes it to the cache. Options 1 and 2 are incorrect because the cache is passive. Option 3 is incorrect because the database doesn't manage the cache.

2. Which scenario makes Redis a superior choice over Memcached?

  • A.When you need to store simple key-value strings only.
  • B.When you require data persistence and complex data structures.
  • C.When you have a strictly read-only workload with no updates.
  • D.When you want the absolute lowest memory footprint without advanced features.
Show answer

B. When you require data persistence and complex data structures.
Redis supports persistence and data structures like sorted sets and hashes, which Memcached lacks. Memcached is only for simple strings, making Option 0 and 3 better suited for Memcached, and Option 2 is not a differentiator.

3. What is the primary benefit of placing a CDN in front of your application?

  • A.It increases the storage capacity of the origin database.
  • B.It reduces latency by serving static assets from edge locations closer to users.
  • C.It encrypts all traffic between the user and the origin server.
  • D.It eliminates the need for any server-side logic in the application.
Show answer

B. It reduces latency by serving static assets from edge locations closer to users.
CDNs cache static content at the edge to shorten the network distance. Option 0 is wrong because CDNs don't expand databases. Option 2 is a feature of TLS, not CDNs. Option 3 is wrong because CDNs cannot replace application logic.

4. In a Write-Through caching strategy, which statement is true?

  • A.The application writes to the cache first, then to the database.
  • B.The application writes only to the database, and the cache is updated later.
  • C.Data is written to both the cache and the database synchronously.
  • D.The application writes to the cache, and the database is updated via a background process.
Show answer

C. Data is written to both the cache and the database synchronously.
Write-Through ensures data is written to both simultaneously, ensuring consistency. Option 0 describes a variation of write-back, Option 1 is standard Cache-Aside, and Option 3 is Write-Behind.

5. What is the consequence of a 'Cache Stampede'?

  • A.The database is overloaded because multiple requests try to regenerate the same expired cache key simultaneously.
  • B.The cache memory becomes fragmented, leading to performance degradation.
  • C.The CDN serves outdated content to users indefinitely.
  • D.The application experiences a timeout while waiting for an external API.
Show answer

A. The database is overloaded because multiple requests try to regenerate the same expired cache key simultaneously.
Cache Stampede happens when a popular key expires and many processes fetch from the DB at once. Option 1 refers to memory management, Option 2 refers to TTL configuration, and Option 3 is unrelated to the cache layer.

Take the full System Design quiz →

← PreviousLoad BalancingNext →Content Delivery Networks (CDN)

System Design

31 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app