Scenarios
Longer problems, like those in senior system design interviews. A strong answer estimates with numbers first, names the mechanism, then recommends a fix and says what it costs.
1At 18:05, a 3-second database stall caused a 40-minute outage of a service that normally runs at 50% utilization. Diagnose and fix it.Show the answer
Estimate
With 3 retries per tier over 4 tiers, the deepest tier can see up to 256 times its normal load. A 3-second stall leaves a queue of requests their clients have already abandoned, which the database needs minutes to drain.
Diagnose
A metastable failure: with an amplification of about 3, the band C / k < λ < C includes 50% utilization. The sustaining loop is retries plus queued work that no one is waiting for.
Recover now
Cut offered load well below C / k (shed at the gateway, or turn off retries), wait for the queue to drain, then ramp up. Do not restart everything: a restart empties caches and adds a cold-start stampede.
Fix the structure
A 10% retry budget on every client, jittered backoff, deadlines carried on each request so expired work is dropped when it is dequeued, bounded queues, and a circuit breaker.
Read moreRetry amplificationWork amplification under loadThe correct recovery procedure
2A pricing cache with a 99% hit rate must be restarted. It serves 20,000 requests per second, and the pricing database comfortably handles 2,000 reads per second. Plan the restart.Show the answer
Estimate
Normally the database sees 1% of 20,000 = 200 requests per second. An empty cache sends all 20,000, ten times what it handles comfortably: the cache's leverage is 100.
Plan
- Warm the new cache from the old one before cutting over.
- Restart in rolling slices, so only part of the key space is cold at once.
- Coalesce requests, one database fetch per key, and allow serving stale values briefly.
- Add jitter to TTLs so keys do not expire together.
- Cap database concurrency with a bounded queue.
Costs
Coalescing makes the first request for each key wait; serving stale data shows old prices for a short time.
Read moreCache stampedeWhy restarting sometimes worksCold-cache collapse
3Your team added 50% more servers, and the system did not become more reliable. Why?Show the answer
Diagnose
The sustaining effect is probably amplification, k, not capacity. More capacity moves only the top of the metastable band (C); k sets the bottom (C / k).
Estimate
With k = 3 and capacity 2,000, the band is 667 < λ < 2,000; with 50% more capacity, 1,000 < λ < 3,000. A little better, but the band is still wide. Worse, more servers can mean more retries and more database connections.
Fix
Reduce k: retry budgets, propagated deadlines, load shedding. Measure k from a past incident: work done divided by useful demand.
4A service depends on 30 internal services, each 99.9% available. Product wants 99.99% for it. What do you propose?Show the answer
Estimate
With all 30 as hard dependencies, the ceiling is 0.999³⁰ ≈ 97.0%, so no amount of redundancy in your own code reaches four nines.
Propose
Turn dependencies into soft ones with fallbacks that are actually exercised (for example, recommendations become optional when rendering a page); remove dependencies from the critical path; isolate by cells; and measure the shared fate that makes the independence assumption false (a shared deploy pipeline, configuration, DNS). Use shuffle sharding where tenants are the source of failures.
Trade-offs
Fallbacks need testing, cells cost multiplexing efficiency, and some dependencies, such as payments, cannot be made soft.
5A thread pool shared by all endpoints runs out when one downstream service slows down. Traffic is 1,000 requests per second at 40 ms each, and the pool has 200 threads. Estimate when it fills, and design the defence.Show the answer
Estimate
By Little's Law, concurrency = throughput × latency: 1,000 × 0.04 = 40 threads busy. If latency rises to 2 seconds, the same traffic needs 2,000 threads, so a 200-thread pool fills in about 0.1–0.2 seconds.
Defend
Bulkheads (a separate pool per dependency), timeouts shorter than the caller's, a bounded queue in front of each pool, and a circuit breaker.
The regime flip
A shared pool is efficient when everything is healthy, and becomes shared fate when one dependency is slow.
Read moreResource-exhaustion cascadeThe regime flip in the shared pool
6Search p99 latency is terrible, yet every health check is green and CPU is flat. How do you find the cause?Show the answer
Suspect
A gray failure: one slow node among 200. A search that fans out and waits for every node is slowed on every query by a single node 100 times slower, while only 0.5% of capacity is lost.
Find it
Build a table of latency by client and server. Compare each node with the median of its peers, and eject nodes above 3 times the median. Add an absolute alert for the case where every node is slow.
Guard the guard
Cap evictions, for example at 20%, so a faulty checker cannot evict everything.
Hedging
It helps only with random stragglers; against a node that is slow for a fixed reason it does nothing but add load.
Read moreDifferential observabilityBound the actionStragglers
7A nightly pipeline exits with code 0, but one city is missing from the dashboard. How do you make the pipeline trustworthy?Show the answer
Diagnose
The exit code is a self-report: it says the control flow finished, not that the data is right.
Fix
Make reconciliation the failure detector: an expected list of cities, row counts compared with the same weekday last week, freshness checks, and a counter for every value coerced to null.
The rule
Every masking mechanism, such as a permissive parser, a retry or a fallback, needs a counter, or it hides failure.
Trade-offs
Compute cost, and expectations that drift, so review the thresholds regularly.
Read moreGray failure in the data planeMasking converts failures into slowness
8Automatic failover keeps flapping between two nodes that both look healthy. What is going on?Show the answer
Explain
A failure detector cannot be correct in an asynchronous system: it sits on one curve trading false alarms against slow detection, and this one is set too far towards false alarms.
Fix
Tune the timeout with an adaptive (phi-accrual style) detector, require agreement from several observers rather than one, add fencing so the old primary cannot write after a failover, and use a watchdog so a hung node stops itself.
Costs
Capacity destroyed by false alarms, and more moving parts.
Read moreFail-stop as a purchased assumptionThe detector sits on one curve
9The p99 latency of a JVM service climbs on its own during a quiet afternoon. Explain, and fix it.Show the answer
Explain
A garbage-collection loop. A pause raises latency; by Little's Law more requests are then in flight, so more data is live; heap occupancy ρ rises; and collection cost, about k ρ / (1 − ρ), rises with it, causing more pauses. Objects promoted prematurely defeat the generational collector. It is metastable.
Fix
Cap concurrency, move large state off the heap or into per-request arenas, and keep heap occupancy low.
Watch
The fleet-level effect, where nodes that pause get ejected and push their load onto the others.
Read moreGC death spiralWhy generational GC fails hereThe fleet-level version
10A 10-minute outage at 80% utilization is followed by a second outage, and then by a third caused by a cold cache. Plan the recovery.Show the answer
Estimate
Draining the backlog takes 10 × 0.8 / 0.2 = 40 minutes at full speed, and catching up at full speed overloads whatever is downstream.
Plan
Drain newest first at a limited rate, drop data that is too stale to matter, and reserve capacity for catching up. Readmit traffic in steps as the cache hit rate climbs, because a cold system's capacity may be 1/50 of a warm one's.
Trade-off
Staleness or lost data, in exchange for stability. Compute the recovery load explicitly before starting.
11Design the overload defences for a booking path.Show the answer
At the edge
Admission control based on queueing delay, with cheap rejection and priority classes.
On every request
Deadlines carried along and checked when work is dequeued.
Retries
At one layer only, from a 10% token bucket, with jitter, and never in response to an overload signal.
Breakers and degradation
Circuit breakers with probing, paired with adaptive concurrency limits; a tested ladder of brownout steps; hedging at p95 with a 5% budget, switched off under overload.
Verify
A game day to test how the defences compose. Autoscaling is a cost tool, not a defence, and every defence is itself a feedback loop.
Read moreLoad sheddingDeadline propagationRetry budgets and circuit breakersBrownout
12An analytics backfill slows down the live dashboards on the same cluster. Fix it without buying a second cluster.Show the answer
Fix
Bulkhead the cluster: a guaranteed floor of capacity for interactive queries plus a shared pool for bursts. Give the backfill the lowest priority, and pace it to a fraction of capacity, adjusted by watching live query latency. Add cost-based admission for large scans.
Trade-off
The backfill takes longer.
Read moreWhat gets partitionedThe cost: isolation versus utilization
13Design how the service should degrade when its primary database is unreachable.Show the answer
Classify dependencies in advance
At design time, mark each dependency as critical or optional, and give each optional one a reachable fallback.
Behaviour
Serve reads from stale data with a visible label ("up to 10 minutes old"); stop the ledger entirely (fail fast).
Test it
With chaos experiments, including injected latency (failing slow, not just failing), because a fallback that rarely runs is the least-tested code you have.
Read moreGraceful degradationChaos testing