Designing a Distributed Cache
High Level Design·intermediate·~22 min read
- system-design
- caching
- distributed-systems
- consistent-hashing
- hld
What you'll learn
1. Problem Statement
Design a distributed in-memory caching system capable of storing 1TB of data, serving 100,000 requests per second with sub-10ms latency, and maintaining high availability across multiple nodes. The system must handle node failures gracef…
Back-of-the-Envelope Estimation
- 1TB data across nodes: if each node holds 64GB usable memory, we need ~16 nodes minimum - 100K requests/second: a single node can handle ~80K ops/sec (single-threaded event loop), so 2-3 nodes suffice for throughput alone - Replication…
2. Requirements
Functional Requirements
- SET(key, value, TTL) -- Store a key-value pair with optional time-to-live - GET(key) -- Retrieve value by key; return null/miss if absent or expired - DELETE(key) -- Remove a key-value pair explicitly - Support variable-size values (by…
Non-Functional Requirements
- Latency: 25% of sampled keys are expired, immediately repeat the scan - Prevents memory from filling with dead keys that nobody reads
4. Data Partitioning (Sharding)
A single machine cannot hold 1TB of data or handle all traffic. We distribute keys across multiple nodes using a deterministic hash function.
Basic Approach
Problem with modulo hashing: When nodes are added or removed, almost every key remaps to a different node. Adding 1 node to a 10-node cluster remaps ~90% of keys, causing a massive cache miss storm (thundering herd to the database). This…
5. Consistent Hashing
The Hash Ring
Consistent hashing maps both nodes and keys onto a circular ring (0 to 2^32 - 1). Each key is assigned to the first node encountered moving clockwise from the key's position on the ring.
Adding/Removing Nodes
When a node is added, only the keys between it and its predecessor on the ring need to move -- roughly 1/N of total keys (where N is the number of nodes).
Virtual Nodes
With only a few physical nodes, the ring has uneven key distribution. Virtual nodes solve this by mapping each physical node to multiple positions on the ring. Why it helps: With 3 physical nodes and no virtual nodes, one node might own…
6. Replication
Each primary node replicates its data to one or more replicas for fault tolerance.
Replication Strategy
Why Asynchronous Replication?
- Synchronous replication would require waiting for all replicas before acknowledging the write -- increases latency from in your API process, and every stage below is a response to a specific pain that killed the previous stage. Walkin…
Stage 1 — MVP: In-process cache in the API server
The simplest thing that could possibly work. - A single API server (monolith) with an in-memory HashMap or LinkedHashMap acting as the cache. - A single relational database (Postgres) behind it. - One client (mobile or web) hitting the A…
Stage 3 — Bottleneck: How do you shard the cache without a re-hash storm?
The first real distributed-cache problem is how to grow past one node's RAM without every capacity change invalidating almost every key. Naïve hash(key) % N sharding remaps ~90% of keys whenever you add or remove a node, and every remapp…
Stage 4 — Second bottleneck: The hot-key / thundering-herd problem
Sharding solves aggregate load, but it does nothing for skewed load. A distributed cache's most characteristic failure mode is a single key — a celebrity user, a viral post, a global config value — receiving 50k+ reads/sec while its assi…
Stage 5 — Third bottleneck: Multi-region latency & cache coherence
Once the service is global, the shared-Redis-cluster-in-one-region model breaks in a new way: a client in Frankfurt does a cache lookup, that lookup crosses the Atlantic to the us-east cluster, and you've just added 90ms of network laten…
Stage 6 — Mature architecture
A distributed cache that has survived Stages 3–5 looks like this: Key pieces to name if you're drawing this on a whiteboard: L1 near-cache in each API pod, L2 Redis Cluster per region with primaries + replicas per shard, a coordination s…
Cost vs Complexity — When to Pick What
| Concern | MVP choice | Growth choice | Enterprise choice | |---------|-----------|---------------|-------------------| | Cache tier | In-process LinkedHashMap | Single managed Redis / ElastiCache node | Redis Cluster per region + L1 ne…
Migration Path (MVP → Enterprise)
You don't build the Stage-6 architecture on day one — you migrate to it in the order the pain shows up. A realistic sequence: 1. Pull the cache out of process. Replace the in-process HashMap with a single Redis node. Cache-aside pattern;…
15. Multi-Region Cache Topology
When scaling a cache globally across multiple data centers, a critical architectural decision is whether to shard the hot dataset across all DCs or fully replicate it within each DC.
The Flawed Approach: Sharding Across Data Centers
If you distribute 10B hot entries across 10 data centers (each DC holding 1/10th of keys), clients will frequently need to query remote DCs for cache lookups. This introduces cross-DC latency (50-200ms) on cache misses -- defeating the e…
The Correct Approach: Full Replication Per Data Center
Each data center maintains a complete copy of the entire hot dataset. This ensures every frontend reads from its local cache cluster with sub-millisecond latency. Trade-off: This uses 10x more servers than a sharded approach, but guarant…
Consistency Across DCs
- Writes go to the central database first - Database propagates updates to all DC cache clusters asynchronously - Maximum staleness window (e.g., 48 hours) controlled via TTL - 99.999% of reads hit fresh data (most updates propagate with…
Capacity Estimation Pattern
---
16. Cache Warmup Strategies
When a cache server restarts or a new node is added, it starts empty. Without warmup, every request becomes a cache miss, sending a burst of traffic to the database -- a thundering herd effect.
Snapshot-Based Warmup
Periodically persist the set of hot keys and their values to disk (similar to Redis RDB snapshots):
Randomized TTLs During Warmup
If all cached entries share the same TTL, they expire simultaneously -- causing a synchronized cache miss storm. Instead, add jitter: This technique applies both during initial warmup and during normal operation to prevent periodic "clif…
Gradual Traffic Ramp
For newly provisioned DCs or major cache rebuilds: 1. Route only 1% of traffic to the new cache cluster initially 2. As hit rate climbs (monitored in real-time), gradually increase traffic share 3. Reach 100% traffic only after hit rate…
17. Redis: Data Types and Practical Knowledge
Redis is the most widely used distributed cache. Understanding its data model and features is essential for system design discussions.
Core Data Types
| Type | Description | Backed By | Use Case | |------|-------------|-----------|----------| | Strings | Binary-safe, max 512MB | Simple dynamic string (SDS) | Counters, session tokens, serialized objects | | Lists | Ordered by insertion,…
Key Commands Quick Reference
Sorted Sets Internals (Skip List)
Sorted sets use a skip list combined with a hash table: - Skip list provides O(log n) insertion, deletion, and range queries - Hash table provides O(1) score lookup by member - Each node exists in multiple "lanes" (levels) for fast trave…
Redis Persistence
Redis is in-memory but supports disk persistence: | Strategy | Mechanism | Trade-off | |----------|-----------|-----------| | None | Pure memory, no persistence | Fastest; data lost on restart | | RDB (Redis Database File) | Periodic poi…
Redis Common Use Cases in System Design
| Use Case | Implementation | Why Redis | |----------|---------------|-----------| | Session Store | String with TTL per session | Sub-ms reads, automatic expiry | | Rate Limiting | Sorted set with timestamp scores | ZRANGEBYSCORE for sl…
Rate Limiting with Sorted Sets (Sliding Window)
This gives precise sliding-window rate limiting with O(log n) per operation.
Redis vs Memcached
| Feature | Redis | Memcached | |---------|-------|-----------| | Data structures | Strings, Lists, Sets, ZSets, Hashes, Streams | Strings only | | Persistence | RDB + AOF | None (pure cache) | | Replication | Master-replica with automat…
Memory Footprint
Use redis-benchmark for load testing, INFO memory for monitoring.