System Design

8) Reliability & resilience — detailed guide

Health checks, graceful degradation, retries & jitter, circuit breakers, bulkheads, rate limiting, backpressure, DR (RTO/RPO), and multi-AZ/region patterns — with a Facebook-like Home Feed example in every section.

A) Health checks & graceful degradation (brownout / bailout)

Health checks (what each one means)

  • Liveness: “Is the process fundamentally broken?” Keep it cheap (event loop alive, threads not deadlocked, heap not exploding). If it fails → restart.
  • Readiness: “Can this instance serve traffic right now?” Check critical deps only (config/secrets loaded, DB reachable, cache reachable). If it fails → remove from load balancer.
  • Startup (K8s): delay readiness until warmup/migrations complete (avoid early 5xx).
  • Pitfalls: deep dependency checks causing cascades; liveness killing pods during long GC.

Graceful degradation

  • Brownout: dim expensive features (turn off heavy ranking features, reduce fanout, fewer candidates).
  • Bailout / Safe mode: serve minimal “core-only” response (cached feed, static shell, limited interactions).
  • Mechanisms: feature flags, kill switches, cached fallbacks, smaller payloads, stale reads with a banner.
Health + degradation — template (what to mention)
Template
• Liveness = restart; Readiness = remove from traffic; Startup = delay readiness during warmup. • Degrade by dropping optional work first (brownout), then safe-mode if needed (bailout). • Make degradation explicit: flags, fallbacks, cached/stale responses + user messaging. • Ensure observability: how often we degrade + why + which feature toggles were active.
Facebook-like Home Feed — health & degradation plan
Example
Readiness: • Feed API is “ready” only if config + Redis + DB are reachable within a small probe budget. Brownout triggers: • If p95 > SLO or Redis CPU > 80% → disable expensive “people you may know” and reduce ranking feature set. • If Kafka lag high → pause non-critical enrichment consumers. Bailout: • If ranking-service is down → serve cached feed head (stale 30–120s) + show “Some content may be delayed.”

B) Retries + jitter, circuit breakers, bulkheads (stop cascades)

Retries (safe rules)

  • Retry only idempotent calls (GET/PUT) or calls with an idempotency key.
  • Use exponential backoff + full jitter to avoid synchronized retry storms.
  • Add a retry budget per request (e.g., don’t burn a 2s SLO on 10 retries).
  • Classify errors: retryable (timeouts/5xx/throttling) vs non-retryable (4xx validation).
Full jitter retry — template
Template
base=50ms; cap=500ms; attempts=3
for i in 1..attempts:
  sleep = rand(0, min(cap, base * 2^(i-1)))
  wait(sleep)
  try request
# Keep total wait bounded by your latency SLO.

Circuit breakers (fail fast)

  • Closed: normal traffic.
  • Open: fail fast when error/timeout/latency crosses threshold.
  • Half-open: allow small probes; close if healthy.
  • Trip on both error rate and p95 latency.

Bulkheads (isolation)

  • Separate pools per dependency (DB pool vs Redis pool), per-tenant concurrency, separate queues for critical vs best-effort work.
  • Prevent “one bad downstream” from consuming all threads/connections.
Retries + breakers + bulkheads — template
Template
• Retries: only idempotent or idempotency-keyed operations. • Backoff: exponential + full jitter; strict retry budget tied to SLO. • Breakers: open on error+latency; half-open probes; fast recovery. • Bulkheads: isolate pools per dependency and per tenant; cap in-flight and queue size. • Goal: stop cascades and preserve the core endpoint SLO.
Facebook-like Home Feed — stop the cascade
Example
Scenario: ranking-service starts timing out. • Breaker opens for ranking-service calls (fail fast). • Feed API switches to fallback: cached ranking / last-known good model output. • Bulkheads keep DB/Redis pools healthy so login + privacy checks still work. • Retries are limited (≤ 250ms total) so we don’t melt the service.

C) Rate limiting, throttling, quotas (protect the system)

Token bucket (most common)

  • Burst up to B, refill at rate r tokens/sec.
  • Deny with 429 and Retry-After; optionally return rate-limit headers.
  • Place it at edge/gateway and also near fragile deps (defense-in-depth).

Leaky bucket / shaping

  • Leaky bucket smooths traffic into fragile dependencies.
  • Great for DB write shaping, email provider, search, third-party APIs.

Quotas and cost-based limiting

  • Per user / per API key / per tenant / per org; reset daily/monthly.
  • Weighted tokens: read=1, write=3, fanout=10, “expensive ranking”=5.
  • Pitfall: only IP-based limits (NAT/office traffic); prefer authenticated identity.
Rate limit — template (what to say)
Template
• Token bucket at the edge for fairness + abuse protection. • Leaky bucket toward fragile dependencies to smooth spikes. • Quotas are identity-based (API key/tenant/user), not IP-only. • Use weighted costs so expensive endpoints can’t starve the system. • Return correct headers (Retry-After) + monitor throttles as a signal.
Facebook-like Home Feed — protect core traffic
Example
• Edge token bucket per user_id for read feed requests (burst allowed for scrolling). • Separate stricter bucket for POST/engagement (likes/comments) to avoid write storms. • Leaky bucket into DB for “write-heavy” actions. • Weighted costs: ranking refresh is expensive → higher token cost than cached feed read.

D) Backpressure (sync services + streams)

Sync services (request/response)

  • Bound everything: request queue, thread pool, DB pool, upstream timeouts.
  • Use watermarks: when queue/in-flight exceeds threshold → return 429/503 early.
  • Adaptive concurrency: tune max in-flight from latency (like “AIMD” behavior).
  • Load shed: drop optional enrichments first; reduce payload size.

Streams (Kafka/Kinesis)

  • Limit in-flight per partition; pause/resume consumption; autoscale on lag.
  • Retry with DLQ, not infinite redelivery loops.
  • Beware “commit before side effects”: commit offsets only after durable success.
Backpressure — template (how to explain)
Template
• Bounded queues/pools everywhere. No unbounded buffers. • Use watermarks: when saturation rises, shed load early with 429/503 (+ Retry-After). • Prefer graceful degradation: drop optional work first. • For streams: cap in-flight per partition, autoscale on lag, DLQ poison messages, commit after side effects.
Facebook-like Home Feed — handling traffic spikes
Example
Sync: • If in-flight > threshold → serve cached feed head; skip “recommendations” enrichment. • If DB pool saturation → 503 with Retry-After for non-critical endpoints. Streams: • If consumer lag > SLO → pause low-priority topics (analytics), keep “privacy updates” high priority. • DLQ malformed events; alert + replay tool.

E) Disaster recovery (RTO/RPO), backups, restore drills

Key terms

  • RTO: time to restore service (e.g., 15 minutes).
  • RPO: max acceptable data loss window (e.g., 60 seconds).

Backups & restore readiness

  • Encrypted, immutable storage (WORM) + cross-region copies.
  • Regular integrity checks and “can we actually restore?” drills.
  • Practice table-level restore and whole-region restore.

Standby patterns

  • Cold: cheapest, slowest recovery.
  • Pilot light: minimal services running, scale up during DR.
  • Warm: partially running, faster failover.
  • Hot: active-active or hot standby; most expensive.
DR — template (what interviewers want to hear)
Template
• Define RTO/RPO per component (DB vs cache vs streams vs object store). • Backups: encrypted + immutable + cross-region + verified. • Drill restores on a schedule (quarterly is a good interview answer). • Script failover: who triggers, cutover steps, DNS/GSLB, promotion with fencing, rollback. • Include secrets/config replication + runbooks + communications plan.
Facebook-like Home Feed — DR stance
Example
Targets: • Feed read path: RTO 15m (can serve cached/stale feed), RPO 5–60s for engagement events. • Privacy settings: stricter RPO (≤ 60s) and safer failover (fail closed if uncertain). Mechanics: • DB snapshots + WAL/CDC replication cross-region. • Quarterly “restore to a new cluster” drill + scripted cutover. • Promote leaders with fencing tokens to avoid split-brain after failover.

F) Multi-AZ vs multi-region (topology choices)

Multi-AZ (within one region)

  • Protects from AZ/rack failure; low latency; simpler operations.
  • Does not protect from full regional outage or provider-wide issues.

Multi-region

  • Protects from regional outage + improves geo latency.
  • Active-passive: simpler invariants (single writer); failover via DNS/GSLB.
  • Active-active: multi-writer; needs conflict handling (CRDT/LWW), idempotency, global IDs.
Multi-AZ vs multi-region — template
Template
• Start with multi-AZ for most systems (cheap reliability win). • Add multi-region if business requires: regulatory, extreme uptime, global latency. • For strict invariants: active-passive (single write region) is simplest. • For eventually consistent domains: active-active can work with conflict resolution + idempotency. • Always test failover and measure the real RTO/RPO.
Facebook-like Home Feed — topology choices
Example
• Feed reads: active-active across regions (serve nearest) with cached/stale tolerance. • Privacy + account controls: active-passive single write region; fail closed during partitions. • Engagement counters: active-active with CRDT merges (likes/views). • Run GSLB with low TTL + region affinity; practice region evacuation.

G) Metrics, SLOs & guardrails (what to monitor + what to automate)

Golden signals

  • Latency: p50/p95/p99 (and tail latency).
  • Traffic: RPS, QPS, bytes in/out.
  • Errors: 4xx/5xx, timeouts, dependency errors.
  • Saturation: CPU, memory, thread pools, connection pools, queue depth.

Protection signals (early warning)

  • Retry rate, breaker opens/flaps, throttles (429), shed rate (503).
  • Queue depth/consumer lag, DLQ rate, replica lag, cache hit ratio drop.
  • Availability of dependencies (DB/Redis/Kafka), slow query rate.

Guardrails & rollouts

  • Canary rollout (1% → 5% → 25% → 100%) with automatic rollback on SLO breach.
  • Error budget burn alerts (fast burn vs slow burn).
  • Feature flags for brownout/bailout with audit trails.
Metrics & SLOs — template (simple way to say it)
Template
• Define SLOs per user journey: read feed, post content, update privacy. • Monitor golden signals + protection signals. • Alert on error-budget burn (fast + slow), breaker flaps, lag SLO, replica lag. • Ship with canaries + auto rollback. Degradation flags are part of the playbook.
Facebook-like Home Feed — SLOs & alarms
Example
SLOs: • Read feed p95 ≤ 200ms; write engagement p95 ≤ 400ms. • 99% of events processed within 5s; DLQ < 0.1%/day. Alerts: • Hit ratio drop > 10%/5m, breaker open > X/min, Kafka lag > threshold, DB pool saturation > 80%. • Error budget fast burn triggers auto rollback and enables brownout flags.

H) Sound bites you can reuse

  • “Readiness isolates bad instances; brownout trims optional work; bailout protects core SLO.”
  • “Retries are budgeted and jittered; breakers and bulkheads prevent cascades.”
  • “Token buckets at the edge for fairness; leaky buckets to shape traffic into fragile deps.”
  • “Backpressure is explicit: bounded queues, early 429/503, autoscale on lag.”
  • “DR is tested restores + scripted failover; RTO/RPO are contractual.”
  • “Multi-AZ by default; multi-region when the business needs it.”
One clean closing line (template)
Template
“I keep the core alive with isolation + backpressure, and I prove it with drills: canaries, failovers, and restore tests.”
Facebook-like Home Feed — 20-second reliability answer
Example
“We protect the feed with readiness checks and graceful degradation. Retries have full jitter and a strict budget, circuit breakers fail fast, and bulkheads isolate dependencies. We rate-limit at the edge, apply backpressure with bounded queues, autoscale on lag, and drill DR with restore + scripted failover (RTO/RPO).”