Deep Dive into Complex System or Project Questions
Being prepared to discuss any significant system or project from your background in detail. Be ready for followup questions testing depth of understanding. Interviewers will probe: What were the constraints? How did you make key decisions? What would you do differently? What surprised you? This validates that your understanding is genuine, not just surface-level.
HardTechnical
34 practiced
Provide a Python script outline or pseudocode to scan streaming logs (multiple GB/hour) and compute the top 10 endpoints by error rate per 1,000 requests across a 24-hour window. Explain streaming/memory considerations and how you would run this as a periodic job.
Sample Answer
Approach (brief): ingest logs as a stream, aggregate counts per endpoint in small time buckets (e.g., 1 minute) for a 24-hour sliding window, compute error rate = errors / requests per 1,000 requests, and maintain a heap/top-10. Use approximate counters (Count-Min Sketch) if cardinality is huge, or exact counters sharded in Redis if feasible. Persist per-bucket aggregates to external store to bound memory.Key considerations:- Memory: per-minute buckets bound memory (WINDOW_BUCKETS * unique endpoints per bucket). If endpoint cardinality is huge, use Count-Min Sketch + heavy-hitter tracking (e.g., Space-Saving algorithm) to approximate top endpoints.- Accuracy: sketches introduce error; tune epsilon/delta. Require exact counts for top candidates by secondary exact counters.- Fault tolerance / scaling: run multiple workers consuming from Kafka partitions; each worker shards by endpoint hash and writes bucketed aggregates to central store (Redis, Bigtable). A reducer job periodically merges shard aggregates to compute final top10.- Periodic job: schedule a job every minute (cron/kubernetes CronJob) to: - read/merge per-minute aggregates for last 24h - compute top10 and push to dashboard/alerting - rotate/expire old buckets (TTL in Redis)- Latency: keep per-minute aggregates to allow near-real-time metrics; for lower latency, use smaller buckets.- Edge cases: burst traffic (hot endpoints) — keep per-endpoint rate limits for counters to avoid OOM, malformed logs, clock skew across workers — use event-time or watermarking in stream frameworks.Alternative: use streaming frameworks (Flink, Spark Structured Streaming) that provide windowing, state backends, and exactly-once semantics; implement same bucketed aggregation there for production.
python
# pseudocode / outline
import time
from collections import defaultdict, deque
import heapq
BUCKET_SECONDS = 60
WINDOW_BUCKETS = 24*60 # 24 hours of 1-min buckets
# in-memory ring of dicts; for production, use Redis/hbase etc.
buckets = deque([defaultdict(lambda: [0,0]) for _ in range(WINDOW_BUCKETS)]) # [requests, errors]
def parse_log(line):
# extract endpoint and status_code
return endpoint, int(status_code)
def process_stream(stream):
current_bucket_idx = int(time.time() // BUCKET_SECONDS) % WINDOW_BUCKETS
last_bucket_start = int(time.time() // BUCKET_SECONDS) * BUCKET_SECONDS
for line in stream:
endpoint, status = parse_log(line)
now = time.time()
bucket_idx = int(now // BUCKET_SECONDS) % WINDOW_BUCKETS
if bucket_idx != current_bucket_idx:
# rotate buckets for each minute passed
steps = (bucket_idx - current_bucket_idx) % WINDOW_BUCKETS
for _ in range(steps):
buckets.popleft()
buckets.append(defaultdict(lambda: [0,0]))
current_bucket_idx = bucket_idx
b = buckets[-1] # current minute
b[endpoint][0] += 1
if status >= 500 or status >= 400: # define "error"
b[endpoint][1] += 1
def compute_top10():
# aggregate across window
agg = defaultdict(lambda: [0,0])
for b in buckets:
for ep,(req,err) in b.items():
agg[ep][0] += req
agg[ep][1] += err
heap = []
for ep,(req,err) in agg.items():
if req >= 1000: # only compute rate per 1000 reqs
rate_per_1000 = (err / req) * 1000
heapq.heappush(heap, (-rate_per_1000, ep, req, err))
top10 = [heapq.heappop(heap) for _ in range(min(10, len(heap)))]
return [(ep, -score, req, err) for score,ep,req,err in top10]HardSystem Design
51 practiced
Design an approach to isolate noisy neighbors in a shared cluster hosting multiple microservices (polyglot workloads). Include resource controls (CPU/memory/shares), QoS classes, cgroup/namespace strategies, scheduling decisions, and monitoring/alerting to detect unseen interference.
Sample Answer
Requirements:- Isolate noisy neighbors while supporting polyglot microservices- Minimize impact on latency-sensitive services, allow best-effort for batch- Detect unseen interference and automate remediationHigh-level approach:1. Admission & resource controls- Enforce CPU/memory requests and limits via Kubernetes LimitRange and ResourceQuota.- Use cgroup v2 features (CFS shares, cpu.max, memory.high/memory.max) at kubelet/containerd level.- Enable CPUManager static policy and reserved CPUs for latency-critical pods (cpuset pinning) to avoid CPU steal.- Use memory.high to trigger proactive throttling and memory.max for hard limits.Example LimitRange snippet:2. QoS and scheduling- Classify pods into Guaranteed (requests==limits), Burstable, BestEffort. Run latency-sensitive services as Guaranteed with dedicated CPUs.- Use node pools (taints/tolerations) and labels: dedicated nodes for Guaranteed, mixed nodes for Burstable/batch.- Use PriorityClasses to protect critical workloads.- Scheduler decisions: affinity/anti-affinity to spread noise, PodTopologySpread, and scheduler profiles to favor low-latency placement. Use Descheduler to evict and migrate noisy pods when needed.3. cgroup/namespace strategies- Leverage cgroup v2 unified hierarchy for precise control; enforce cpu.max and memory.high per container.- Use network namespaces + traffic shaping (tc) to limit noisy network consumers.- Use RuntimeClass to select runtimes with different isolation (gVisor for untrusted tenants).4. Detection & monitoring- Metrics: - Node: CPU steal, load, frequency, softirq, page faults, NUMA imbalance - Container: cgroup cpu.stat (nr_periods, throttled_time), memory.oom_kill, memory.pressure, blkio latency, network queues- Tools: Prometheus + node_exporter/cadvisor + eBPF (bcc/tracee) to detect syscall saturation, cache-misses, and tail latency. Collect perf counters for cache/memory hot spots.- Alerts: - High container throttling rate (throttled_time/periods > threshold) - CPU steal > X% on nodes hosting Guaranteed pods - Memory.pressure or high page-faults - Tail latency SLI breach (p95/p99)5. Automated remediation- Graceful throttling: automatically lower BestEffort/Burstable limits via Vertical Pod Autoscaler or scale down HPA for noisy tenants.- Evict/migrate offending pods with Descheduler + cordon/drain policy to isolate.- If persistent, move noisy workloads to separate node pool or apply cpuset pinning.- Provide feedback loop: annotate offending deployments and notify owners via alerting/incident playbook.Trade-offs:- Strict pinning increases fragmentation and reduces bin-packing efficiency.- gVisor increases latency; use only for untrusted workloads.Why this works:- Combines proactive placement (dedicated CPUs/nodes), reactive controls (cgroups, throttling), and deep telemetry (eBPF, cgroup stats) to both prevent and detect noisy neighbor effects while allowing automated, owner-notified remediation.
yaml
apiVersion: v1
kind: LimitRange
spec:
limits:
- type: Container
defaultRequest:
cpu: "100m"
memory: "128Mi"
default:
cpu: "500m"
memory: "512Mi"MediumTechnical
37 practiced
For your system, explain the load-balancing architecture at each layer you used (DNS, global LB, L4/L7 proxies, client-side), how you handled session affinity, health checks, and geo-routing, and what failure modes you observed and mitigations you put in place.
Sample Answer
Situation: I designed the multi-layer load‑balancing stack for a global, containerized service to meet SLOs for latency and availability.Architecture (per layer)- DNS: Authoritative DNS with low but not-zero TTL (60s) + DNS-based geo-routing (GeoDNS) to point clients to nearest region. DNS records used as coarse failover; health of regions fed into DNS via automation.- Global LB: Anycasted global frontends (cloud provider/global CDN) terminated TCP/SSL and performed region selection using BGP/latency metrics and health signals; acted as the first failover boundary.- L4 proxies: Regional L4 load‑balancers (cloud NLB / metal haproxy) provided fast TCP routing and handled connection draining for host replacement; used consistent-hashing for stateful TCP flows.- L7 proxies: Envoy sidecars / regional ingress performed TLS termination, routing, rate‑limiting, retries, and advanced routing (path/host/headers). They also implemented circuit breakers and per-route timeouts.- Client-side: SDK with smart retries, exponential backoff, and multi‑region fallback (preferred region header + failover to alternate endpoint).Session affinity- Primary: HTTP cookie-based affinity at L7 (secure, signed cookies) for web sessions.- For TCP/stateful flows: consistent hashing on connection 5-tuple at L4 to map to backend pools.- Fallback: source-IP affinity only when cookies absent, with TTL-limited mappings and sticky buckets to avoid long-lived hotspots.Health checks- Active: HTTP/GRPC health endpoints (readiness vs liveness) polled by L4/L7 and global LB with configurable success thresholds and consecutive failures.- Passive: Proxy-level monitoring of error rates/latency (e.g., consecutive 5xx or high p50/p99) to mark hosts unhealthy faster than active checks.- Kubernetes: readiness probes to avoid routing to pods still initializing; preStop hooks + connection drain for graceful termination.- Automated rollout gating: CI/CD blocked if synthetic health checks fail.Geo-routing- Primary: GeoDNS + global LB using latency and capacity-aware routing; weighted traffic shifting for gradual failover.- Secondary: Client SDK can request a particular region via header if needed (e.g., regulatory constraints).- Failover: Automated region failover with circuit-break thresholds and traffic-splitting to limit blast radius during partial outages.Observed failure modes and mitigations- DNS caching/TTL delays: low TTL (60s) and active health-to-DNS updates; for stubborn caches we used weighted failover at global LB to route traffic away faster.- Hotspots from session affinity: short sticky TTLs, consistent-hash redistribution, capacity autoscaling, and per-backend rate limits.- Slow drain leading to connection drops on deploys: enforced connection-draining windows, preStop hooks, and draining metrics before SIGTERM.- False positives from naive health checks: layered passive health detection and multi-metric checks (error rate + latency + success threshold) to avoid flapping.- Global LB/Anycast partial failures: multi-provider anycast + regional fallback, and runbooks for BGP/peering incidents.- Cascading failures from retries: implemented idempotency keys, bounded retries at client and proxy, and exponential backoff with jitter.- Control-plane partitioning: automated multi-region control-plane with read-only fallback and operator escalation path.Key outcomes- Reduced failover time from minutes to <60s for region outages, lowered 95th-percentile tail latency by isolating hotspots, and improved availability during deployments with zero user-visible downtime for 90% of deployments.
MediumTechnical
36 practiced
How did you measure and reduce rollout risk for significant releases? Describe the canary metric selection, automated checks during canary, rollback triggers, health verification, and any manual gating used before wider rollout.
Sample Answer
Situation: At my previous company we rolled a new authentication service that touched every user request — high blast radius, so we needed a safe canary strategy.Approach / Metric selection:- I picked three tiers of canary metrics: safety (errors, 5xx rate, auth failures), latency (p50/p95/p99 for auth flows), and business impact (login success rate, conversion funnel drop-off). Each metric had an SLO baseline and an allowable delta (e.g., 5xx rate must not increase >0.5% absolute).- Added secondary metrics: downstream queue lengths, CPU/memory, DB error rates to catch resource regressions.Automated checks during canary:- Implemented a pipeline that deploys to 1% of users then 10% using feature-flag routing.- Continuous checks run for 15 minutes at each step: compare metrics vs baseline using statistically-aware detectors (EWMAs + seasonal-aware anomaly detector) and hypothesis tests for significance.- Integration smoke tests run: synthetic logins, token refresh, edge-case inputs.Rollback triggers:- Immediate automatic rollback for critical thresholds (e.g., absolute 5xx >1% or login success drop >2%).- Graceful rollback for softer breaches (e.g., latency p95 up >50ms): alert paging and hold progression.- Rollback action is automated through orchestration (K8s rollout undo + feature-flag flip) with a single command to minimize MTTR.Health verification & manual gating:- After automated pass at 10%, an SRE/PM triage panel reviews dashboards for 30–60 minutes, verifies no hidden regressions, and approves progression to 50%+.- For high-risk releases we required an on-call SRE in the loop and a “go/no-go” checklist: canary metrics green, no emergent alerts, and successful chaos-tests on a replica environment.Outcome & learnings:- This reduced incidents during deploys by ~70% and average rollback time to <7 minutes. Key learning: pick business-impactful canary metrics and automate the easy decisions while keeping humans for judgment calls.
HardTechnical
37 practiced
Describe an incident involving a thundering herd or cache-stampede that affected availability. Explain detection signals, immediate mitigations you applied (locking, request coalescing, rate-limiting), and permanent design changes to prevent recurrence.
Sample Answer
Situation: During a major marketing campaign our web service suddenly experienced a 10x traffic spike to a product-detail endpoint. Cache hit ratio collapsed and backend API (database + downstream search) saturated, causing 5–10s tail latencies and 30% of requests timing out.Detection signals:- Sudden spike in cache miss rate (>80% → 95%) in our Redis cluster- Concurrent jump in origin QPS and connection count- P50/P95 latency increase and elevated 5xx on the service- Pager alert: origin error-rate SLO breachedImmediate mitigations I applied (within minutes):- Enabled circuit-breaker on calling layer to fail fast and protect origin- Put a short, global rate-limit (token-bucket) on requests that miss cache for the affected key pattern to reduce origin pressure- Implemented request coalescing (singleflight) at the service edge for identical cache keys so only one backend fetch proceeded while others waited with a timeout- Used a Redis-based mutex (SETNX + short TTL) for fetching-and-populating the cache where singleflight unavailable- As emergency fallback, served stale cached values (stale-while-revalidate) for a short grace window so users still got responsesPermanent design changes:- Introduced cache stampede protections: - Layered singleflight library in service code for per-key coalescing - Redis lock helper with backoff and observable metrics (lock-acquire latency, failures) - Stale-while-revalidate policy: return slightly-stale data while refreshing async - Add randomized TTL jitter to prevent synchronized expirations- Capacity & autoscaling changes: - Hardened origin autoscaling and set graceful queueing limits - Improved rate-limiting rules scoped per-key and per-customer- Observability & runbook: - New dashboard showing miss-rate, lock contention, revalidation latency, and origin saturation per key pattern - Runbook with playbook steps: flip stale mode, enable singleflight, tighten rate-limits- Testing & chaos: - Added load tests for cache expiry scenarios and chaos experiments that expire hot keys to validate protectionsOutcome: After fixes, origin QPS dropped 70%, tails returned to normal within 20 minutes, and subsequent planned spikes showed no recurrence thanks to coalescing + stale-while-revalidate + jitter. Learned to treat hot-key expiry as a first-class failure mode and instrument per-key metrics proactively.
Unlock Full Question Bank
Get access to hundreds of Deep Dive into Complex System or Project interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.