Articles
Memcached Interview Questions: Eviction, CAS, and Cache Failure
Practice Memcached eviction, CAS retries, and cache failure with worked timelines, TTL traps, slab diagnostics, and database fallback load calculations.
A strong Memcached interview answer explains what happens after a key disappears, two writers race, or the cache stops answering. Start with three boundaries: expiration is not guaranteed retention, CAS protects a single cached item, and an unavailable cache must not become an unlimited invitation to query the database.
Evidence boundary: linked vendor documentation establishes official behavior. The timelines, load calculations, and design recommendations below are original interview exercises and engineering inference. We do not use candidate reports to claim that a particular employer asks these questions.
What does Memcached actually own?
Question: “We stored the account balance in Memcached. Is the write complete?”
Ask whether the cache contains a derived view or the only copy of the balance. The first can be rebuilt; the second makes eviction a correctness failure. A sound application contract names an authoritative source, a permitted staleness interval, and the behavior when the cached representation cannot be read.
Official fact: the user guide describes application-managed cache lookup and population rather than automatic database acceleration. An application must distinguish a missing item from legitimate cached values such as zero or false.
Inference: cache a product's display price if the checkout path validates the authoritative price. Do not authorize a payment from a cached balance merely because the lookup is fast. The same cached field can be acceptable for display and unacceptable for a decision.
An interviewer may ask whether Memcached “has persistence.” Avoid an absolute answer based on an old comparison chart. Official fact: configured warm restart can preserve items across compatible clean restarts, but the documentation explicitly says that this does not make Memcached crash safe. Updates missed during downtime also matter.
Your application should therefore tolerate a cold cache even if the deployment uses restart preservation. Retaining a cache can reduce recovery work; it does not replace the source of truth or guarantee a coherent snapshot of ongoing application writes.
Why can an item disappear before its TTL?
Question: “The TTL is one hour. Why did the item disappear after five minutes?”
Separate expiration, eviction, invalidation, and routing. Expiration ends eligibility because time passed. Eviction frees space under memory pressure. A delete or flush invalidates items deliberately. A client routing change can send a lookup to another server that never held the item.
Official fact: Memcached's maintenance guide documents eviction of still-live items and per-slab statistics. A long TTL does not reserve memory. A zero TTL disables time-based expiration; it does not disable eviction.
Official fact: the performance guide explains allocation into size classes. Consequently, an overall memory number alone can hide pressure affecting items in one class. Modern reassignment features mean that a simplistic “pages never move” explanation should not be treated as a universal current configuration rule.
Original diagnostic exercise: a release changes serialized profile objects from roughly 700 bytes to roughly 1,400 bytes. Misses and evictions increase, but request volume is unchanged. Before buying memory, compare item-size distribution, class allocation, and whether the larger objects are actually reused. The release may have doubled useful data, added unnecessary fields, or crossed a class boundary with more internal waste.
A helpful answer pairs observations with tests:
| Observation | Candidate explanation | Next evidence |
|---|---|---|
| Evictions rise in a size class | Useful working set no longer fits | Class pages, item sizes, recent-use evidence |
| Misses rise without evictions | Expiration, new keys, or routing changes | TTL settings, key versions, client server list |
| Errors rise while misses stay flat | Transport or server saturation | Timeout phase, connections, CPU, network |
| Cache falls cold after deployment | Restart or deliberate invalidation | Restart logs and flush counters |
These are hypotheses, not proofs. A cache miss does not contain its cause; instrumentation around writes, invalidation, and routing supplies the missing context.
What is the 30-day expiration trap?
Question: “Why did setting a 45-day TTL make the item immediately unavailable?”
Official fact: the user guide's expiration rules interpret values up to 30 days as relative seconds and larger values as Unix timestamps. Forty-five days expressed as a bare duration can therefore be interpreted as a date near the beginning of the Unix epoch.
In an original exercise, 45 * 24 * 60 * 60 equals 3,888,000. That number exceeds the relative-duration boundary. It is not “45 days from now” under this protocol rule. For a longer lifetime, use the correctly computed absolute expiration expected by the client and server.
Check the client API as well: a wrapper may accept a date, a duration object, or an integer and convert it. Explain both layers rather than assuming the wrapper exposes the wire format unchanged. A test should inspect the resulting expiry behavior across the boundary, not merely assert that the arithmetic produced the intended number.
Walk through a CAS conflict
Question: “Two requests append different tags to the same cached profile. Does get, modify, set preserve both?”
No. Both can read the same value and then overwrite one another. Official fact: the basic text protocol provides gets to retrieve an item's CAS identifier and cas to conditionally store a replacement when the identifier still matches.
Original exercise: the starting tags are [green]. Treat token numbers as illustrative opaque identifiers, not application versions.
| Step | Request A | Request B | Cached state |
|---|---|---|---|
| 1 | Reads tags, token 41 | Reads tags, token 41 | [green], token 41 |
| 2 | Computes [green, amber] | Computes [green, blue] | Unchanged |
| 3 | CAS with 41 succeeds | Waiting | [green, amber], new token 42 |
| 4 | Done | CAS with 41 fails | A's update remains |
| 5 | Done | Rereads and recomputes | Can attempt [green, amber, blue] |
The key move is recompute from the newly read value. Retrying B's previously calculated replacement with a new token would still remove A's contribution.
Inference: bound the retry count and preserve the request deadline. Under sustained contention, repeated CAS attempts can waste work. For a commutative operation, a supported atomic operation or a different authoritative model may be more appropriate than replacing a large object repeatedly.
CAS does not atomically update two keys, commit a database transaction, or guarantee that an item remains present. If the application stores derived data, ask whether merging cached tags is even correct: rebuilding from the authoritative record may be safer than turning the cache into an independent writer.
What if the item vanished between gets and CAS?
Question: “A had a valid token, but the item was evicted before its replacement arrived. Should A blindly call set?”
Distinguish a changed existing item from a missing item. The token only has meaning while the server can compare it against the corresponding item. An unconditional replacement after failure discards that protection.
Original recovery reasoning: if the item is a cached database view, reread the source and attempt population. If another request has already populated it, an add-if-absent operation can avoid overwriting that newer cache entry. If the item is application-owned ephemeral state, define whether disappearance means restart the operation, return an error, or recreate a specifically initialized value.
A bounded conceptual loop is:
read item and token
if missing:
rebuild from authoritative source
attempt add-if-absent
else:
derive replacement from this read
attempt CAS with this token
on conflict:
reread and recompute within deadline
on transport error:
apply the error policy, not the conflict policy
The last line matters. A rejected comparison and a lost response are different events. The server may have applied a mutation whose response the client never received. Ask whether retrying the operation is harmless, whether it needs an operation identifier, and whether the cached item is sufficiently authoritative to answer that question.
How should a cache outage affect database traffic?
Question: “We can always fall back to SQL, so why is a cache outage dangerous?”
Original capacity exercise: suppose a service receives 10,000 reads per second and normally has a 95% hit rate. Ignoring refreshes, the database receives about 500 reads per second. A completely cold or unavailable cache can send it toward 10,000 reads per second: twenty times the usual miss traffic.
If the database has 1,500 reads per second of safe capacity for this endpoint, unrestricted fallback is not recovery. It moves the incident to the database. Under these assumptions, you need to admit or serve differently at least 8,500 requests per second during the outage. That is an admission budget, not a universal Memcached benchmark.
Inference: combine a short cache deadline with a database concurrency limit, a circuit breaker, and a defined degraded response. Some requests can use an independently retained stale representation within a freshness policy. Others must wait briefly or fail. Security-sensitive decisions cannot silently accept stale data just to preserve the hit rate.
Coalescing concurrent misses for the same key helps a hot-key stampede, but it does not solve 10,000 distinct-key misses. TTL jitter helps synchronized expiry, but it does not restore an unreachable node. Name the failure mode before naming the mechanism.
Is a timeout just another miss?
Official fact: Memcached's timeout troubleshooting guide discusses multiple causes, including connection handling and host or network problems. “Increase the timeout” is not a diagnosis.
Inference: record hit, miss, rejected mutation, connection failure, and command timeout separately. If all are counted as misses, a cache outage can look like poor key reuse. If all errors are retried, a broken node can receive even more pressure.
For a request with 200 milliseconds remaining, spending 150 milliseconds retrying the cache leaves little budget for a database lookup. Choose an end-to-end deadline first, then allocate it across cache, source, and response work. Retry counts alone do not bound latency when each attempt has a long timeout.
An interview follow-up may offer a distributed lock implemented with add. Explain that an evictable, expiring lock needs ownership checks, bounded use, and a correctness model. It should not be treated as a durable fence protecting irreversible writes. The meta protocol also provides cache-specific anti-stampede mechanisms; using one requires compatible client support and does not eliminate application-level failure handling.
Sources and Further Reading
- Memcached user guide and expiration rules
- Basic text protocol: retrieval and conditional storage
- Maintenance: hit rates, eviction, and slab statistics
- Performance and item memory allocation
- Warm restart and crash-safety limitations
- Troubleshooting client timeouts
- Meta text protocol and anti-stampede features