Distributed Cache System Design Template
Distributed cache: cache-aside, delete on write, leases against herds, commit-log invalidation across regions, slot maps, hot keys, gutter pool, warm-up
Cách dùng: Use it when designing a shared cache tier in front of databases for read-heavy traffic. Fill the database's tolerable miss rate and the hit-ratio target first, because they drive leases, failure handling and warm-up. The main pitfall is setting values on write and rehashing on node failure, which create stale data and cascading misses.
Xem trước
System Design: [Distributed cache name]
Reference design for a shared, in-memory distributed cache tier that sits in front of databases and services in read-heavy workloads. It covers the cache-aside (look-aside) pattern, leases against stale sets and thundering herds, invalidation across clusters and regions, consistent hashing and slot maps, hot keys, warm-up of cold clusters, and failure handling with a small standby ("gutter") pool. Concepts draw on "Scaling Memcache at Facebook" (Nishtala et al., NSDI 2013); the text and the worked design are original. It follows the structure of the System Design Document template. Replace every
[bracketed]value and every row marked Example.
Document control
| Field | Value |
|---|---|
| Document ID | [SDD-CACHE-001] |
| System / feature | [Shared cache tier for profile and content reads] |
| Version | [0.1] |
| Status | [Draft / In review / Approved / Implemented / Superseded] |
| Owner | [@owner] |
| Author(s) | [@author] |
| Reviewers | [@reviewer-1], [@reviewer-2] |
| Last updated | YYYY-MM-DD |
| Classification | [Internal] |
| Consistency target | [Example: Eventual, stale reads bounded to seconds; read-your-writes for the writer] |
| Related | Distributed Key-Value Store System Design (system-design/design-distributed-kv-store), CDC Pipeline System Design (system-design/design-cdc-pipeline), Resilience and Load Shedding Design (system-design/resilience-load-shedding-design) |
Approvals
| Role | Name | Decision | Date |
|---|---|---|---|
| Tech lead | [@name] | [Approved / Changes requested] | YYYY-MM-DD |
| Staff / principal engineer | [@name] | [Decision] | YYYY-MM-DD |
| SRE / operations | [@name] | [Decision] | YYYY-MM-DD |
| Database owner | [@name] | [Decision] | YYYY-MM-DD |
| Security | [@name] | [Decision] | YYYY-MM-DD |
Revision history
| Version | Date | Author | Change summary |
|---|---|---|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft for design review |
| 0.2 | YYYY-MM-DD | [@name] | Example: Switched from set-on-write to delete-on-write after stale-data incident |
| 0.3 | YYYY-MM-DD | [@name] | Example: Added gutter pool instead of rehashing on node failure |
| 1.0 | YYYY-MM-DD | [@name] | Example: Approved |
Contents
1. Overview
1.1 Problem statement
[Example: Each service runs its own cache cluster with its own conventions. Writers update cache values after writing the database, and races leave stale profiles for hours. When a popular item expires, thousands of requests miss at once and the database falls over. A single cache node failure moved a third of the keys to other nodes and caused a cascade of misses.]
1.2 Proposed solution
[Example: A shared cache tier of stateless-looking, memory-only cache servers, organised in clusters per region. Clients use cache-aside: read the cache, on a miss read the database and fill the cache with a lease token so that stale fills are rejected and only one client per hot key refills it at a time. Writers never set values; they delete keys, and deletes are also generated from the database commit log and fanned out to every cluster and region. Keys map to servers through a versioned slot map. A small gutter pool absorbs traffic for failed servers so their keys do not move. New clusters warm up by reading through a warm cluster.]
1.3 Decisions requested from reviewers
| ID | Question | Recommended option | Section |
|---|---|---|---|
| Q-01 | Example: Cache pattern? | Cache-aside with delete on write | 7.1 |
| Q-02 | Example: How to stop thundering herds and stale fills? | Leases issued by the cache server | 7.2 |
| Q-03 | Example: Who sends invalidations? | Commit-log-driven delete stream, plus TTL as a safety net | 7.3 |
| Q-04 | Example: What happens when a node dies? | Gutter pool, no rehashing | 7.4 |
| Q-05 | Example: Replicated or partitioned clusters per region? | Partitioned within a cluster; several clusters per region for read scale | 6, 8 |
| [Q-nn] | [Question] | [Option] | [Section] |
1.4 45-minute interview path
| Minutes | Cover | Output on the whiteboard |
|---|---|---|
| 0 to 5 | Read/write ratio, staleness tolerance, what the database can absorb | Core requirements, hit-ratio target |
| 5 to 10 | Throughput, memory, hot keys, fan-out | 64 nodes, throughput-bound; hot key needs replication |
| 10 to 18 | Cache-aside flow and topology diagram | Section 6 diagram |
| 18 to 33 | Deep dive: leases (7.2) and invalidation across regions (7.3); if the interviewer pushes on availability, use failure handling and warm-up (7.4) | Lease sequence, delete stream |
| 33 to 40 | Hot keys and multi-get fan-out | L1 cache, replication, batching |
| 40 to 45 | Trade-offs and 10x | Table in section 10 |
2. Requirements
2.1 Core functional requirements
| ID | Requirement | Priority |
|---|---|---|
| FR-01 | Example: Get and multi-get of up to 500 keys per call | Must |
| FR-02 | Example: Fill on miss with protection against stale fills and herds | Must |
| FR-03 | Example: Delete keys from any writer and from the database commit log | Must |
| FR-04 | Example: Propagate deletes to every cluster in every region | Must |
| FR-05 | Example: Writers read their own writes on the next request | Must |
| FR-06 | Example: Per-namespace TTL and memory quota | Should |
| FR-07 | Example: Bulk invalidation of a namespace by bumping its version | Should |
| [FR-nn] | [Requirement] | [Must / Should / Could] |
2.2 Non-functional requirements
| ID | Quality | Target | Measured as |
|---|---|---|---|
| NFR-01 | Latency | Example: p99 below 1 ms for get, below 5 ms for a 100-key multi-get | Client-side histograms |
| NFR-02 | Hit ratio | Example: at least 98% for the profile namespace | Server counters |
| NFR-03 | Staleness | Example: 99.9% of deletes applied in all regions within 5 s | Probe writes |
| NFR-04 | Database protection | Example: Database read QPS never above 300 000, even during cache failures | Database metrics |
| NFR-05 | Availability | Example: Loss of one cache node raises database load by under 2% | Chaos test |
| [NFR-nn] | [Quality] | [Target] | [Measurement] |
2.3 Below the line (out of scope)
- [Example: Durable storage; the cache may lose any data at any time (see
system-design/design-distributed-kv-storefor durable key-value storage)] - [Example: Transactions or compare-and-set across keys]
- [Example: Caching personalised HTML at the edge (handled by the CDN)]
- [Example: Strong consistency for money or inventory; those reads go to the database]
- [Item deferred, with the release that will take it]
3. Capacity estimation
3.1 Assumptions
| Input | Symbol | Value | Source |
|---|---|---|---|
| Peak cache reads per second (keys) | Example: 10 million | Client metrics x growth | |
| Peak writes per second (database) | Example: 200 000 | Database metrics | |
| Keys invalidated per write | Example: 2 | Key derivation rules | |
| Cached items in the working set | Example: 2 billion | Key sampling | |
| Average item size incl. overhead | Example: 500 B | Server stats | |
| Usable memory per node | Example: 64 GB | Instance type | |
| Operations per second per node | Example: 200 000 | Benchmark | |
| Keys per page request (multi-get) | Example: 100 | Trace sampling |
3.2 Hit ratio and database load
At , database reads/s; at , /s. Consequence: a drop of 8 points in hit ratio multiplies database reads by five and breaks NFR-04, so the design spends most of its complexity keeping the hit ratio stable when keys expire (leases), when nodes fail (gutter) and when clusters are new (warm-up).
3.3 Nodes
Consequence: the tier is throughput-bound, not memory-bound, so choose instances with more CPU and network per GB, and use the spare memory (66 nodes x 64 GB, about 4.2 TB against a 1 TB working set) to cache a longer tail and raise the hit ratio.
3.4 Network and fan-out
Total read bandwidth is B GB/s, about 76 MB/s per node, which is modest. Fan-out is the real cost: with 100 keys spread over 66 nodes, the expected number of distinct nodes touched is
Consequence: a page waits for the slowest of about 52 parallel requests, so tail latency of single nodes dominates (incast). Batch per node, cap outstanding requests per client, and group keys that are read together (same hash tag) where the data model allows it.
3.5 Hot keys
A viral item read 1 million times per second exceeds one node's 200 000 ops/s by five times. Consequence: hot keys need replication (several copies under suffixed keys) or a client-side L1 cache with a 1 s TTL; with 2 000 web servers each refreshing once per second, the cache tier sees about 2 000 reads/s for that key instead of 1 million.
3.6 Summary
| Quantity | Estimate | Design consequence |
|---|---|---|
| Database reads at 98% hit | 200 000/s (1 million/s at 90%) | Leases, gutter and warm-up protect hit ratio |
| Nodes | 66, throughput-bound | CPU-heavy instances; spare memory raises hit ratio |
| Multi-get fan-out | ~52 nodes per page | Per-node batching, flow control, key co-location |
| Hot key | 5x one node's capacity | L1 cache and hot-key replication |
| Deletes | 400 000/s | Batched delete stream through routers |
4. API design
4.1 Client operations
| Operation | Returns | Notes |
|---|---|---|
get(key) | value or miss | |
multi_get(keys) | map of found values | Batched per node, parallel across nodes |
lease_get(key) | value, or miss with lease token, or wait hint, or stale value plus stale flag | See 7.2 |
lease_set(key, value, token, ttl) | stored or rejected | Rejected if token was invalidated by a delete |
delete(key, hold_off_ms = 0) | deleted or not_found | Optional hold-off rejects fills for a short period |
touch(key, ttl) | ok | Extend TTL |
bump_namespace(ns) | new version | Logical bulk invalidation |
4.2 Read path in code
def read_profile(user_id):
key = f"profile:v3:{user_id}"
r = cache.lease_get(key)
if r.hit:
return r.value
if r.wait: # another client holds the lease
sleep_ms(r.retry_after_ms) # short backoff, then one retry
r2 = cache.get(key)
if r2.hit:
return r2.value
value = db.read_profile(user_id) # one database read
if r.token:
cache.lease_set(key, value, r.token, ttl=3600)
return value
Write path: commit the database transaction, then delete(key). The commit
log consumer (7.3) deletes the same key again everywhere; deletes are
idempotent, so the duplicate is harmless.
4.3 Admin API
| Method and path | Purpose |
|---|---|
GET /v1/slotmap | Current slot-to-node map and version |
PUT /v1/slotmap | Publish a new version (rebalance, replace node) |
PUT /v1/namespaces/{ns} | TTL, memory quota, hot-key replication factor |
POST /v1/clusters/{id}:warmup | Start or stop warm-up from a named warm cluster |
5. Data model
5.1 Keys and values
Keys follow {namespace}:{schema_version}:{entity_id}[:{variant}], for
example profile:v3:918273 or feed:v2:918273:page1. The schema version in
the key lets a deploy that changes the value format read new keys while old
ones expire. Values carry a small header:
| Field | Purpose |
|---|---|
fmt | Serialisation format and version |
written_at | Diagnostics; age histograms |
src_version | Database row version or commit position, for debugging staleness |
payload | Serialised object, compressed above Example 1 KB |
Server-side lease state is kept in memory per key: token, issued time, and whether a delete has invalidated it.
5.2 Storage choices
| Data | Store | Key | Why |
|---|---|---|---|
| Cached objects | In-memory cache servers with LRU per slab class | Cache key | Sub-millisecond reads |
| Hot-key copies | Same servers, keys suffixed #r0 to #r7 | Cache key + replica suffix | Spread one key over several nodes; a delete must reach every suffix |
| Slot map | Coordination service (system-design/design-distributed-lock-coordination), cached in routers and clients | Version number | Consistent routing across all clients |
| Remote markers | Regional pool | rm:{key} | Read-after-write in replica regions (7.3) |
5.3 Access patterns
| Access pattern | Served by | Partition key and rationale |
|---|---|---|
| Read one profile | profile:v3:{user_id} on slot hash(user_id) | Entity ID gives uniform spread |
| Read a page of 100 objects | Multi-get, batched per node | Keys co-located by hash tag only when always read together; otherwise spread for balance |
| Read a viral item | L1 client cache, then one of 8 replicas item:{id}#r{n} | Random replica per client spreads load |
| Invalidate after a write | Delete by key from commit log consumer | Same key derivation in writer and consumer library |
| Invalidate a whole namespace | Bump ns version stored in the coordination service | Old keys age out by TTL and LRU |
| Check read-after-write in replica region | rm:{key} in the regional pool | One small marker per recently written key |
6. High-level design
| Component | Responsibility | Scales by |
|---|---|---|
| Client library + L1 | Key derivation, leases, multi-get batching, tiny hot-key cache | With clients |
| Cache routers | Route by slot map, batch, fail over to gutter, fan out deletes | Stateless replicas |
| Cache clusters | Store items; several clusters per region each hold the full key space | Nodes per cluster, clusters per region |
| Regional pool | One copy per region for large, rarely read items and remote markers | Nodes |
| Gutter pool | Short-TTL stand-in for failed nodes (about 1% of servers) | Nodes |
| Commit log consumer | Turn committed row changes into key deletes (system-design/design-cdc-pipeline) | Log partitions |
7. Detailed design
7.1 Deep dive: caching pattern and write handling
| Option | How it works | Strength | Weakness |
|---|---|---|---|
| A. Cache-aside, set on write | Writer updates database, then sets the new value | Fresh immediately | Two concurrent writers can set out of order; stale value stays until TTL |
| B. Cache-aside, delete on write | Writer updates database, then deletes; next reader fills | Deletes are idempotent and commute | One extra miss after each write |
| C. Read-through | Cache fetches from the database itself | Simple clients | Cache must know every data source |
| D. Write-through | Writes go through the cache to the database | Cache always populated | Write latency; cache on the write critical path |
| E. Write-behind | Cache acknowledges, persists later | Fast writes | Data loss on cache failure; wrong for a memory-only tier |
Choice: B. Reason: deletes are safe under any interleaving and any duplication, which matters because deletes arrive from writers and again from the commit log; the remaining race (a reader fills a value it read before the write) is closed by leases in 7.2.
7.2 Deep dive: leases against stale sets and thundering herds
Two problems happen on a miss:
- Stale set: reader A misses and reads version 1 from the database; writer B commits version 2 and deletes the key; A then sets version 1, which stays until TTL.
- Thundering herd: a hot key is deleted or expires; thousands of readers miss at once and all query the database.
| Option | Fixes stale set | Fixes herd | Cost |
|---|---|---|---|
| A. Short TTLs only | Bounds staleness | No | More misses |
| B. Version check on set (compare with database version) | Yes | No | Version per value; extra logic in writers |
| C. Client-side request coalescing | No | Per client only | Herd across clients remains |
| D. Server-issued leases | Yes | Yes | Server state per missing key; client retry logic |
| E. Probabilistic early refresh | No | Mostly | Background refresh load |
Choice: D. Reason: one mechanism fixes both problems at the server that sees every request for the key.
- On a miss, the server returns a lease token bound to the key.
- A delete of that key invalidates outstanding tokens, so a fill based on an older read is rejected.
- The server issues at most one token per key per interval (Example 2 s);
other clients get a short
waithint and retry, by which time the lease holder has usually filled the value. - For data classes that tolerate it, the server keeps a recently deleted
value and returns it marked
staleinstead ofwait, so readers never block.
Set the lease interval and wait hint from measured database read latency for the namespace; a hint shorter than the database read creates repeated retries.
7.3 Deep dive: invalidation across clusters and regions
Several clusters per region each hold the full key space, and replica regions read from replica databases. A delete must reach every copy.
| Option | How it works | Strength | Weakness |
|---|---|---|---|
| A. TTL only | Values expire | No infrastructure | Staleness equals TTL |
| B. Writer broadcasts deletes | Application deletes in every cluster and region | Immediate | Writer crash loses deletes; writers need every endpoint |
| C. Commit-log-driven deletes | A consumer of the database commit log derives keys and deletes them through routers in each region | Reliable (replayable), no writer coupling | Key derivation must be shared code; small delay |
| D. Versioned keys | Key includes data version; readers look up version first | No deletes needed | Extra lookup per read |
Choice: C plus the writer's own local delete and a TTL safety net. Reason: the commit log is the only place every committed change appears exactly once in order, so invalidations become as reliable as replication; the writer's local delete gives read-your-writes in its own cluster.
In replica regions the replica database may lag; a reader that misses could fill the cache from a replica that has not yet seen the write. Two measures:
- Deletes in replica regions are produced from the replica's commit log, so they arrive after the replica has applied the change.
- For read-your-writes, the writer sets a short-lived remote marker for the key in the regional pool before writing; a reader in that region that misses and finds the marker reads from the primary region's database instead of the local replica. The marker is removed when the change replicates or by TTL.
7.4 Deep dive: partitioning, failure handling and warm-up
Key distribution options:
| Option | How it works | Rebalance cost | Notes |
|---|---|---|---|
A. hash mod N | Node = hash(key) mod N | Almost every key moves on change | Unusable at scale |
| B. Consistent hashing ring with virtual nodes | Each node owns many ring points | About 1/N of keys move | Even load needs many virtual nodes |
| C. Rendezvous hashing | Highest score of hash(key, node) wins | About 1/N of keys move | O(N) per lookup without tricks |
| D. Slot map | hash(key) mod 16 384 slots; slots assigned to nodes in a versioned map | Move chosen slots explicitly | Map must be distributed consistently |
Choice: D. Reason: explicit slot moves make rebalancing a planned, observable operation, hot slots can be moved alone, and the map version lets routers detect stale routing.
Failure options:
| Option | What happens on node loss | Risk |
|---|---|---|
| A. Rehash keys to remaining nodes | Lost node's keys spread to others | Moved keys miss; a hot key can overload its new node, causing cascading failures |
| B. Replicate every key | Replica serves | Doubles memory and delete fan-out |
| C. Gutter pool | Routers send that node's traffic to a small dedicated pool; entries there have a short TTL and are not invalidated | Short staleness for affected keys |
Choice: C. Reason: failures stay contained to a pool sized for them, other nodes keep their keys and hit ratios, and the database sees only the first miss per key. A permanent replacement is done by a planned slot-map change.
Cold cluster warm-up: a new or emptied cluster reads misses from a warm cluster in the same region and adds the value locally, instead of going to the database. Deletes to the cold cluster use a short hold-off (Example 2 s) during which adds are refused, so a value that the warm cluster has not yet invalidated cannot be copied in; a refused add sends the reader to the database. Turn warm-up off when the cold cluster's hit ratio stabilises.
7.5 How real systems do it
How real systems do it (paraphrased, not copied). Nishtala and colleagues describe Facebook's memcache deployment in "Scaling Memcache at Facebook" (NSDI 2013). The cache is a demand-filled look-aside cache and writers delete rather than update. Memcached hands out leases on misses: a delete invalidates the token so late fills are refused, and tokens for a key are issued only every few seconds so most concurrent readers wait briefly instead of hitting the database. A small Gutter pool, around one percent of cache servers, takes over for failed servers with quickly expiring entries, avoiding the rehashing that can cascade. Invalidations come from daemons that tail the database commit log and are batched through routers. Rarely accessed items can share one regional pool, new clusters warm up from existing ones using deletes with a hold-off, and replica regions use remote markers to send reads of just-written keys to the master region. This template reuses the ideas, not the text or figures.
8. Scalability and performance
| Concern | Approach | Limit before redesign |
|---|---|---|
| Read throughput | Add nodes to a cluster or add clusters per region | Delete fan-out grows with clusters |
| Memory | Larger instances or more nodes; regional pool for cold large items | Working set beyond cluster memory lowers hit ratio |
| Hot keys | L1 cache, replica keys, automatic hot-key detection by sampling | One key above L1 refresh x clients |
| Fan-out | Batch per node; co-locate keys read together | Pages with thousands of keys need a precomputed aggregate |
| Connections | Routers multiplex client connections | Router count |
| Invalidation rate | Batched deletes per node | Example: 400 000 deletes/s x clusters x regions |
Latency budget for one get (NFR-01, Example): client library 0.05 ms, router hop 0.2 ms, server 0.05 ms, network 0.3 ms, headroom 0.4 ms. Remove the router hop for the hottest services by running the router as an in-process library.
9. Reliability, security and operations
9.1 Failure-mode table
| Component | Failure | Detection | Blast radius | Mitigation | RTO |
|---|---|---|---|---|---|
| Cache node | Crash | Router health checks | That node's slots, about 1/66 of keys | Gutter pool, then slot-map replacement | Example: seconds to gutter; 30 min to replace |
| Whole cluster | Lost or flushed | Hit ratio collapse | One cluster's clients | Shift clients to other clusters; warm-up from warm cluster | Example: 15 min |
| Commit log consumer | Stalled | Delete lag metric | Staleness everywhere up to TTL | Restart from committed position; deletes replay | Example: 5 min |
| Hot key | Single key overloads node | Per-key sampling, node CPU | Every key on that node | Promote to replicated key; L1 | Example: 1 min automated |
| Slot map | Bad version published | Routing error rate | All clients | Versioned rollback; staged publish | Example: 2 min |
| Database | Overloaded by misses | Database QPS and latency | All services | Leases, load shedding (system-design/resilience-load-shedding-design), serve stale | Depends on cause |
| [Component] | [Failure] | [Signal] | [Scope] | [Mitigation] | [Time] |
9.2 Security
| Threat | Control |
|---|---|
| Unauthenticated access to cache servers | Private network only; TLS and client authentication between routers and servers |
| Cross-tenant reads | Namespaces per service; router enforces which namespaces a client may use |
| Sensitive data in memory | Do not cache secrets or full payment data; encrypt sensitive values with a service key |
| Cache poisoning via user-controlled keys | Keys derived by the library from typed IDs, never from raw input |
| [Threat] | [Control] |
9.3 Observability
| Signal | Metric | Alert threshold |
|---|---|---|
| Hit ratio | Per namespace and cluster | Example: below 96% for 10 min |
| Database protection | Database read QPS | Above 250 000/s |
| Latency | p99 get and multi-get per client | Above NFR-01 for 10 min |
| Invalidation | Delete lag from commit to apply, per region | Above 5 s at p99 |
| Leases | Wait hints and rejected sets per second | Doubling vs. baseline |
| Evictions | Evictions of items younger than 1 h | Rising trend means memory is short |
10. Trade-offs and alternatives
| Decision | Options | Chosen | Why | What we give up |
|---|---|---|---|---|
| Write handling | Set; delete | Delete on write | Safe under reordering and duplicates | One miss after each write |
| Herd and stale fills | TTL; version checks; leases | Leases | Fixes both at the server | Retry logic in clients |
| Invalidation source | Writers; commit log; TTL | Commit log + local delete + TTL | Reliable and replayable | Shared key-derivation code |
| Distribution | Ring; rendezvous; slot map | Slot map | Explicit, observable moves | Map distribution |
| Node failure | Rehash; replicate; gutter | Gutter | Contained blast radius | Brief staleness on gutter |
| Product | Self-built; open-source cache servers; managed service | [Choice] | [Reason] | [Cost] |
| At 10x load | 100 million reads/s | More clusters per region and larger fan-out batches; precomputed aggregates for pages with many keys; L1 for more namespaces | Fan-out and delete fan-out grow faster than reads | More clusters to invalidate |
| At 0.1x load | 1 million reads/s | One cluster of about 7 nodes per region; leases and commit-log deletes still worth it; gutter can be one node | Simpler topology | Less isolation between services |
11. Delivery plan and risks
11.1 Milestones
| Milestone | Scope | Exit criterion | Target date |
|---|---|---|---|
| M1 | Client library with leases, one cluster, profile namespace | Hit ratio at least 98%; no stale profiles in sampled checks | YYYY-MM-DD |
| M2 | Commit-log deletes in primary region; writers switch to delete | Delete lag p99 under 1 s | YYYY-MM-DD |
| M3 | Gutter pool and slot-map rebalancing | Node-kill drill meets NFR-05 | YYYY-MM-DD |
| M4 | Replica regions, remote markers, warm-up | Cold cluster reaches 95% hit ratio without database spike | YYYY-MM-DD |
11.2 Rollout and rollback
[Example: Migrate one namespace at a time behind a flag that chooses the old or new client library. Rollback flips the flag; both tiers receive deletes during migration so neither serves stale data after a switch.]
11.3 Risks
| ID | Risk | Likelihood | Impact | Mitigation | Owner |
|---|---|---|---|---|---|
| R-01 | Example: Key derivation differs between writer and commit-log consumer | Medium | High | One shared library; contract tests | [@name] |
| R-02 | Example: Teams cache data that needs strong consistency | Medium | High | Review per namespace; documented data classes | [@name] |
| R-03 | Example: Gutter pool undersized for a rack failure | Low | High | Size for the largest failure domain; drill | [@name] |
| R-04 | Example: Lease wait hints add latency to hot pages | Medium | Medium | Stale-value mode for tolerant namespaces | [@name] |
| [R-nn] | [Risk] | [L / M / H] | [L / M / H] | [Mitigation] | [@name] |
12. Appendices
12.1 Open questions
| ID | Question | Owner | Due |
|---|---|---|---|
| OQ-01 | Example: Which namespaces may receive stale values on lease wait? | [@name] | YYYY-MM-DD |
| OQ-02 | Example: Is a second gutter pool per rack needed? | [@name] | YYYY-MM-DD |
| [OQ-nn] | [Question] | [@name] | YYYY-MM-DD |
12.2 Glossary
| Term | Meaning |
|---|---|
| Cache-aside (look-aside) | The application reads the cache and fills it from the source on a miss |
| Lease | A token a cache server gives on a miss; required to fill the key and invalidated by deletes |
| Thundering herd | Many clients missing the same key at once and overloading the source |
| Gutter pool | Small set of servers that stands in for failed servers with short-lived entries |
| Slot map | Versioned assignment of hash slots to cache nodes |
| Remote marker | Short-lived flag that a key was just written, used to route reads to the primary region |
| Hold-off | Period after a delete during which adds for that key are refused |
| [Term] | [Meaning] |
12.3 Related templates
- Distributed Key-Value Store System Design (
system-design/design-distributed-kv-store): durable storage, when a cache is not enough. - CDC Pipeline System Design (
system-design/design-cdc-pipeline): commit-log stream that drives deletes. - Distributed Lock and Coordination Service System Design (
system-design/design-distributed-lock-coordination): slot map and configuration storage. - Resilience and Load Shedding Design (
system-design/resilience-load-shedding-design): protecting the database when the cache fails. - Back-of-Envelope Estimation (
system-design/back-of-envelope-estimation): method behind section 3.
12.4 References
| Reference | Use |
|---|---|
| Nishtala R. et al., "Scaling Memcache at Facebook", 10th USENIX Symposium on Networked Systems Design and Implementation (NSDI '13), 2013 | Leases, gutter pool, commit-log invalidation, regional pools, cold cluster warm-up, remote markers (7.2 to 7.5) |
| Kleppmann M., Riccomini C., Designing Data-Intensive Applications, 2nd ed., 2026 (inspiration only) | Background on derived data and caching |
Standard and licence note
Based on the publicly described techniques in the NSDI 2013 memcache paper cited in 12.4 and on common industry practice; no standard governs cache tiers. This is a reference design to adapt, with illustrative numbers marked Example. Original text written for this collection; sources were used as inspiration only and no text, figures or diagrams were copied. Check the current documentation of the cache software you adopt. Template licence: MIT.
Template liên quan
Distributed Key-Value Store System Design Template (Dynamo-Style)
Consistent hashing, vnodes, quorums (R+W>N), vector clocks vs LWW, hinted handoff, Merkle anti-entropy, gossip, LSM compaction, cache eviction, hot keys
Thiết kế hệ thốngDistributed Lock and Coordination System Design Template
Lock and coordination service: Raft consensus, read index, sessions and keep-alives, leader election, fencing tokens, watches, read scaling, misuse policy
Thiết kế hệ thốngZanzibar-Style Authorization Service System Design Template
Relationship-based authorization service: relation tuples, namespace config, Check/Expand/List/Watch APIs, consistency tokens, caching, sharding, failure modes