Infrastructure Scaling, Capacity Planning, and High Availability Questions
Making infrastructure grow and stay up: horizontal and vertical scaling, autoscaling, load balancing, capacity planning and forecasting, and high-availability and redundancy design. Covers sizing systems for demand, distributing load, and eliminating single points of failure so services remain available as they scale. The reliability-and-growth discipline.
New autoscaled instances repeatedly fail health checks because the application cold-start is >2 minutes. Propose a redesign of autoscaling and LB interaction to meet SLAs while minimizing cost. Discuss baked AMIs/container images, warm pools, lifecycle hooks (initialization before registration), container image pre-pull, and alternative architectures such as serverless for burst handling.
Sample Answer
Requirements & constraints:
- SLA: instances must pass LB health checks within <2 min.
- Minimize cost while supporting bursts and steady baseline.
- Keep deployment velocity and reliability.
High-level redesign:
- Reduce cold-start time (application ready before registration) using baked images + lifecycle hooks + warm pool.
- Change autoscaling-LB interaction: only register instances/containers to LB after readiness probe passes (deferred registration).
Components and implementation:
-
Baked AMIs / container images:
- Bake runtime, OS patches, language runtimes, dependencies, and a precompiled application artifact into AMIs or container images via CI pipeline (Packer, kaniko). This shrinks initialization from minutes to seconds.
- Tag images with version + health-test script.
-
Warm pool (managed pre-warmed capacity):
- Maintain a small pool of stopped-but-ready AMIs or running-but-drained instances/containers sized to handle typical spike M (based on traffic percentiles).
- For ASG (EC2): use Auto Scaling Warm Pools to keep instances in stop/standby with booted AMI snapshot fast-start.
- For containers: keep N idle warm tasks in ECS/EKS with scheduler affinity but not registered to service.
-
Lifecycle hooks / initialization before registration:
- Use autoscaling lifecycle hooks (or container lifecycle hooks) to run initialization (DB migrations, cache priming, JIT, TLS cert loading) before completing lifecycle and registering to LB.
- Health lifecycle: a custom readiness check endpoint that confirms full app readiness. Only after success call CompleteLifecycleAction / register target group.
-
Container image pre-pull:
- On host bootstrap (user-data) or via DaemonSet, pre-pull images to avoid image download latency. Use local registry mirror and layered caching.
- For serverless containers (Fargate): use warm tasks or provisioned concurrency.
-
LB interaction changes:
- Configure LB health checks to use readiness endpoint separate from basic instance up check.
- For blue/green or rolling updates, deregister instance only after draining connections and background jobs finished.
Alternative architectures for bursts:
- Serverless / provisioned concurrency:
- Offload bursty request paths to Lambda (or Cloud Run) with provisioned concurrency to eliminate cold-start for critical endpoints.
- Use API Gateway + Lambda for short-lived stateless endpoints; keep stateful or long-start services on instances.
- Hybrid: baseline handled by minimal fleet + warm pool; scale bursts to serverless or spot instances for cost efficiency.
Operational concerns & metrics:
- Monitor time-to-ready, lifecycle hook duration, image pull times, and LB failure rates.
- Autoscaling policy: combine target tracking (latency/queue depth) with predictive scaling based on traffic forecasts to pre-warm.
- Cost trade-offs: warm pool and baked images increase baseline cost but reduce failed health checks and SLA penalties. Use spot for non-critical warm instances.
Edge cases:
- Long initialization tied to external services — mock/health-check those dependencies or lazy-init after registration with circuit breakers.
- Cache warming: run synthetic traffic to prime caches during lifecycle hook.
This design ensures nodes/containers are only put into rotation when fully ready, uses pre-baked artifacts and warm pools to reduce cold-starts, and provides a serverless burst-offload path to minimize cost while meeting SLAs.
Describe a step-by-step approach to measure a service's baseline performance before doing capacity planning. Include what metrics to collect (p50/p95/p99 latency, error rates, CPU, memory, IOPS, network), how to create isolated test environments, and how to avoid confounding variables (noisy neighbors, caching differences).
Sample Answer
- Define objective & traffic profile
- Decide target transactions, peak vs steady, read/write mix, request distribution, and SLAs (e.g., 99th < 500ms).
- Prepare isolated test environment
- Provision dedicated test infra that mirrors production (same instance types, OS, JVM/configs, storage class).
- Use IaC (Terraform) to create throwaway environments to avoid noisy neighbors.
- Disable autoscaling/auto-healing or document behavior so results are deterministic.
- Baseline warmup and configuration parity
- Warm caches (app, DB, CDN) with representative traffic until metrics stabilize.
- Ensure configs (thread pools, GC, DB connection pools) match prod.
- Instrumentation & metrics to collect
- Latency percentiles: p50, p95, p99 per API/endpoint.
- Error rates: HTTP 5xx, application exceptions, retries.
- Resource: CPU, memory (heap/non-heap), GC pause times.
- I/O: disk IOPS/latency, queue depth.
- Network: throughput, packet loss, RTT.
- System-level: load average, context switches.
- Business metrics: requests/s, concurrency, success rate.
- Collect with Prometheus, Datadog, or similar; trace with OpenTelemetry.
- Load testing and measurement plan
- Run incremental load tests: ramp-up, steady-state, spike, and soak tests.
- For each stage capture all metrics; run multiple iterations to detect variance.
- Avoid confounding variables
- Isolate noisy neighbors: use dedicated hosts or pinned CPUs; avoid multi-tenant noisy VMs.
- Control caching differences: test both cold and warm cache scenarios, clear caches between runs when measuring cold-start.
- Fix background jobs and cron tasks; schedule tests when external dependencies are stable (or mock them).
- Network: use controlled network (same AZ, consistent routing) or simulated latency consistently.
- Analysis & repeatability
- Plot p50/p95/p99 vs load to find knee/throughput ceiling.
- Correlate latency spikes with CPU, GC, IOPS, network.
- Document test harness, seed data, and exact config; save raw metrics and dashboards.
- Repeat after configuration changes; use results to size headroom (e.g., target 30–40% utilization at expected peak).
This gives a repeatable baseline to guide capacity planning and trade-offs (scale vertically vs horizontally, caching, sharding).
Architect a system to handle promotional traffic spikes that reach 100x baseline for short durations without keeping 100x capacity provisioned. Describe autoscaling strategy, buffer/pool strategies, caching and CDN pre-warm, queueing/backpressure, graceful degradation (feature gating), and cost controls. Define the metrics and acceptance criteria to validate the architecture.
Sample Answer
Requirements & constraints:
- Handle 100x baseline traffic bursts lasting minutes–hours without provisioning 100x steady capacity.
- Maintain acceptable latency for high-value flows (e.g., checkout), degrade best-effort flows.
- Cost constrained; autoscale quickly but avoid runaway bills.
- Safety: no data loss, predictable backpressure.
High-level architecture:
Client -> CDN (edge + WAF) -> API Gateway / Load Balancer -> Edge Cache + Rate-Limit layer -> Ingress Queue (durable) -> Autoscaled Worker Fleet / Service Pool -> DB / Stateful services (with write-sharding, read replicas, caches)
Autoscaling strategy:
- Multi-layer autoscaling:
- Fast scale on stateless frontends using target tracking (CPU/RPS) + predictive scaling based on scheduled promotions and traffic pattern models.
- Worker pool: mix of warm standby instances (small fleet at 2–5x baseline) + rapid scale-out (autoscaling group with fast instance types or container tasks). Use predictive spin-up when promotions are known.
- Scale based on business signals: queue length, request latency, 95/99th pct response time, and custom metric "requests per second per worker".
- Warm pool / buffer:
- Maintain a small warm pool of pre-initialized containers/VMs (e.g., 5–10% or absolute minimum) to reduce cold-start time.
- Use spot/ephemeral for extra capacity with fallback to on-demand.
Buffering & queue strategies:
- Place a durable ingress queue (Kafka/SQS/RabbitMQ) for non-real-time work; frontdoor converts bursty synchronous calls into queue + async responses where acceptable.
- Use token-bucket rate limiting and per-customer quotas at gateway to protect downstream.
- Backpressure: when queue depth > threshold, return 202 (accepted) or 429 with Retry-After for low-priority requests; prioritise high-value requests via priority queues.
Caching & CDN pre-warm:
- Cache static assets and computed promo pages at CDN edge. Pre-warm by issuing synthetic requests to edge POPs before promotion start (or use CDN API prefetch).
- Edge compute (Lambda@Edge/CloudFront Functions) to serve personalization tokens with minimal origin trips.
- Aggressive TTLs for immutable content; use cache-busting for targeted dynamic content.
Graceful degradation (feature gating):
- Define degradation levels:
- Level 0: normal
- Level 1: disable non-essential analytics, low-priority personalization
- Level 2: convert some sync flows to async, show "busy" placeholders
- Level 3: limited checkout features reserved for logged-in/high-value users
- Implement feature flags + traffic steering to gate features dynamically via control plane based on metrics.
Cost controls:
- Use mixed instance types: on-demand for baseline + spot for burst capacity with automated fallbacks.
- Budget alerts and hard caps: autoscaler respects cost-aware caps; prioritize essential services when hitting spend thresholds.
- Prefer caching/CDN and queuing to save origin compute cost.
- Implement TTLs and cache-control headers to reduce origin load during burst.
Metrics & acceptance criteria:
- Metrics to monitor:
- RPS, 50/95/99 latency, error rate (4xx/5xx), queue depth, worker utilization, cold-start count, cache hit ratio, cost per hour.
- Acceptance criteria during a 100x simulated burst:
- Latency: 95th percentile for critical flows ≤ baseline * 2 or fixed SLA (e.g., ≤ 500ms)
- Error rate: <1% for critical flows; overall error rate <5%.
- No data loss: zero lost messages in durable queues.
- Time to scale: worker capacity to meet 90% of incoming work within acceptable window (e.g., <120s).
- Cache hit ratio increase at edge ≥ X% reducing origin RPS by >80%.
- Cost: incremental cost during burst within predefined budget limits (e.g., ≤ 10x baseline cost for short bursts) and alerts triggered if exceeded.
Validation plan:
- Run chaos tests and load tests with production-like traffic patterns including spikes, cold starts, and spot interruptions.
- Simulate promotion schedule to validate predictive scaling and CDN pre-warm.
- Execute failure scenarios: DB replica lag, spot termination, queue retention overflow to ensure graceful degradation paths work.
Trade-offs:
- Aggressive caching/pre-warm reduces origin load but can complicate personalization.
- Spot capacity is cheap but unreliable—must be backstopped by on-demand.
- Queuing increases end-to-end latency for best-effort flows but preserves system stability.
This design balances responsiveness, resilience and cost by combining predictive/warm autoscaling, durable buffering, CDN pre-warm, prioritized queueing, and staged graceful degradation governed by measurable acceptance criteria.
Explain how service discovery integrates with load balancers in microservices architectures. Compare DNS-based discovery, client-side discovery with registries (Consul/Eureka), and server-side discovery with gateways or service meshes. For each pattern describe how instances register/deregister, how the LB learns about backends, and how to handle TTLs and stale entries.
Sample Answer
High-level: service discovery tells clients or load balancers how to find healthy service instances. There are three common patterns — DNS-based, client-side with a registry, and server-side (gateway/service-mesh). I’ll compare them on registration/deregistration, how the LB learns backends, and TTL/stale-entry handling.
- DNS-based discovery
- Registration: instances register a DNS A/AAAA or SRV record (manually or via automation like Route53/Consul DNS). Deregistration: instance removes record or TTL expires.
- How LB learns backends: clients or external LBs resolve DNS names; LB uses result set to pick targets. Many resolvers cache records.
- TTL / stale entries: rely on DNS TTL. Short TTL (e.g., 5–30s) reduces staleness but increases query load. For SRV, you get port metadata. Need health checks upstream because DNS alone doesn’t encode liveness beyond record removal.
- Client-side discovery with registries (Consul, Eureka)
- Registration: instances register themselves with a registry (HTTP API/agent) and send heartbeats or pass health checks. Deregistration: explicit deregister on shutdown or automatic eviction after missed heartbeats.
- How LB learns backends: the client queries the registry for available instances and load-balances locally (round-robin, sticky, weighted). No central LB; each client acts as load balancer.
- TTL / stale entries: registry enforces TTLs/health checks; clients should handle failures and refetch periodically. Implement caching with short TTL + circuit breaker/backoff to avoid pounding the registry. Use watches/events to get incremental updates.
- Server-side discovery (gateway, cloud LB, or service mesh like Envoy/Istio)
- Registration: instances register with a control plane (service registry) or local sidecar/agent updates the central proxy. For meshes, sidecars subscribe to control-plane xDS streams.
- How LB learns backends: the gateway/proxy (centralized LB) queries the registry or receives push updates and maintains the pool; it performs load balancing, retries, outlier detection, and can do L7 routing.
- TTL / stale entries: control plane enforces health checks; proxies receive incremental updates and apply TTLs. Sidecars often implement connection draining and graceful removal (remove from LB, wait for in-flight requests to finish). Service mesh supports active health checks and outlier detection to avoid stale or flapping instances.
Trade-offs and guidance
- DNS: simplest and broadly supported; poor for fast churn and L7 metadata.
- Client-side: lowest latency and high flexibility but pushes complexity to clients and can duplicate logic.
- Server-side/mesh: centralizes policy and observability, supports advanced LB (circuit breakers, retries), but adds operational surface and latency from proxy hops.
Operational best practices
- Use health checks and short but practical TTLs (balance freshness vs query load).
- Implement graceful deregistration (pre-stop hooks) so LBs stop sending new requests and drain connections.
- Combine patterns when useful: e.g., DNS pointing to regional gateways, registries for intra-cluster discovery, and a mesh for L7 features.
Create a high-level capacity planning checklist and estimation approach for a stateless web service expected to handle 5,000 requests/sec with p95 latency target of 200ms. Include how to benchmark per-instance throughput, calculate required instance counts, account for autoscaling buffer and headroom, load balancer capacity, and database/backend dependencies that affect sizing.
Sample Answer
Situation: You need a concise, reproducible capacity plan for a stateless web service targeting 5,000 req/s with p95 ≤ 200ms.
Checklist & estimation approach
- Clarify requirements & constraints
- Target throughput: 5,000 req/s
- Target p95 latency: 200 ms (end-to-end)
- SLAs (availability), deployment model (k8s/VMs), instance types, cost constraints.
- Benchmark per-instance throughput (practical steps)
- Use realistic traffic (payloads, auth, headers) and representative backend (or a mock with realistic latency).
- Tools: k6, wrk, JMeter. Gradually ramp to find max RPS where p95 ≤ 200ms.
- Monitor CPU, memory, network, GC, threads, connection pools, and p95/p99 latencies.
- Record sustained throughput at p95 target and failure modes (CPU saturation, queueing).
- Calculate raw instance count
- Let per_instance_rps = measured sustainable RPS at p95 200ms.
- Required_instances_raw = ceil(target_rps / per_instance_rps)
- Example: if per_instance_rps = 500 → 5000/500 = 10 instances.
- Add buffers & headroom
- Autoscaling buffer for spikes and scaling latency: +20–30%.
- Headroom for rolling deploys/evictions: +10–20%.
- Total factor ≈ 1.3–1.5. Example: 10 * 1.3 = 13 → round to 14 or 15 for safety.
- Autoscaler config & operational concerns
- Min instances = enough to handle base load (e.g., 60–70% of avg traffic).
- Max instances = ceil(required * safety cap).
- Configure cooldowns, warm-up probes, and pre-warming if cold starts are slow.
- Load balancer & network limits
- Verify LB can handle 5k+ RPS and concurrent connections (per-LB throughput, sockets/sec).
- If using multiple LBs, distribute accordingly; ensure health-checks won’t overload instances.
- Check NAT, LB connection limits and TLS termination CPU costs (offload if needed).
- Downstream/database and external dependencies
- Translate 5,000 req/s into DB queries/QPS (read/write ratio). Example: 1 req -> 0.5 writes + 1 read => DB QPS = 5,000*(1.5)=7,500 QPS.
- Ensure DB replicas, connection pool sizing, and cached layers (Redis, CDN) can sustain QPS with acceptable latencies.
- If DB latency increases, it will reduce per-instance throughput; include this in benchmarks.
- Final verification and runbook
- End-to-end stress test (load generator → LB → instances → DB) to validate p95 and failure modes.
- Define alerting thresholds (CPU, latency, error rates) and autoscale policies.
- Document rollback, capacity increase steps, and cost impact.
Quick numeric example:
- Measured per-instance = 500 RPS at p95 200ms.
- Raw = 5000/500 = 10.
- Add 30% buffer → 13 → choose 15 instances (round up, allow maintenance).
- Validate LB & DB capacity for 5k RPS and ~7.5k DB QPS; scale DB or add cache if needed.
This plan gives a repeatable flow: benchmark realistically, compute base capacity, add operational buffers, validate end-to-end, and capture autoscaling/runbook details.
Unlock Full Question Bank
Get access to all Infrastructure Scaling, Capacity Planning, and High Availability interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.