Performance Cost Optimization & Resource Efficiency Questions
Optimizing for the money and resources a given level of performance consumes, not just raw speed. Covers cost-per-request, training-cost and cost-per-inference reasoning, right-sizing and cost-driven autoscaling of compute, memory and storage, choosing between on-demand, reserved and spot capacity, storage tiering and egress-cost reduction, cloud-bill diagnosis and reduction plans, and cost allocation or chargeback across teams and tenants. A question belongs here when the primary deliverable is a cost or resource-consumption calculation, decision or reduction plan, not when cost is one line among several unrelated technical considerations. Distinct from defining or measuring latency, percentiles, SLOs and latency budgets on their own, from profiling and bottleneck diagnosis such as flame graphs, hotspots and query tuning, from production incident and on-call triage, from general multi-axis trade-off frameworks where cost is incidental to a decision about latency, freshness or complexity, from concurrency, batching and thread-safety mechanics, and from garbage-collection and memory-leak tuning: those are covered by dedicated sibling topics.
Serverless functions in production suffer occasional cold starts that violate a 100ms P95 latency SLO. Walk through the mitigation techniques you would consider, the cost and operational trade-offs of each, and an experimental plan to measure whether each approach meets the SLO while minimizing incremental cost.
Sample Answer
Mitigation techniques and their trade-offs
- Provisioned concurrency: keeps a set number of function instances always warm, directly eliminating cold starts for covered traffic. Cost: billed continuously for the provisioned capacity regardless of use, so it's the most effective and most expensive option, worth it only if sized to real, predictable load.
- Keep-alive or scheduled warmers: a periodic ping that invokes the function to stop the platform from fully shutting the instance down. Cheaper than provisioned concurrency, paying only for occasional ping invocations, but weaker: it typically keeps one instance warm, not enough concurrency to cover a real burst, and providers can still recycle instances despite the pings.
- Reducing package size and lazy initialization: trims what has to load before the function can serve a request, a smaller deployment artifact and deferring imports or connections until actually needed. No ongoing cost, just engineering time, and it shrinks a cold start's magnitude even when one does happen, but it can't eliminate cold starts, only reduce them.
- Runtime or language choice: some runtimes have measurably faster initialization paths than others; switching is a one-time engineering cost with no ongoing bill impact, but is often the most disruptive change to make on an existing service.
Experimental plan
- Establish a baseline: measure current p95 latency (the value below which 95% of requests complete) and per-invocation cost with no mitigation, using real production traffic or a faithful replay of it.
- Roll out each mitigation to a small percentage of traffic behind a feature flag, one at a time where possible, so effects don't get conflated.
- For each variant, measure the same two numbers: whether p95 latency now meets the 100ms SLO (service level objective, the internal latency target the team commits to), and the incremental cost per invocation, provisioned concurrency's continuous charge divided by invocations it served, or the negligible cost of a warmer or package change.
- Run each variant long enough to cover normal traffic variance, including at least one low-traffic period, since that's when provisioned concurrency's utilization, and therefore its cost efficiency, is worst, before deciding.
- Roll forward the cheapest variant that meets the SLO; if the low-cost options alone don't close the gap, add provisioned concurrency sized to the observed baseline concurrency from step 1, not a guess.
Cross-region replication of frequently read content has driven up network egress costs for a global service. Design an architecture that reduces cross-region egress while preserving read latency guarantees for regional users, and explain the consistency trade-offs your design introduces.
Sample Answer
Direct answer
Replace full cross-region replication of every read with a regional read cache or read replica in front of the frequently-read content, so most reads are served locally without violating read latency guarantees for regional users, and pay for the reduced egress with an explicit, named consistency model instead of assuming replication is free.
Structured elaboration
Architecture: keep one authoritative write region, or a small set of write regions if multi-writer support is genuinely required elsewhere, and place a regional read-through cache or read replica in each region with frequent regional read traffic. Writes propagate asynchronously to fill the regional read layer, instead of every read crossing back to the source region.
Component roles: the primary store is the source of truth for writes; a regional cache or replica per region serves the large majority of reads locally, refreshed either by a push, a replication stream, or a pull, a cache TTL (time-to-live); and an invalidation or refresh path is what actually determines the consistency guarantee, not a side detail to leave undefined.
flowchart LR
W[Write request] --> P[(Primary store, source of truth)]
P -- async replication or cache fill --> RA[Regional cache A]
P -- async replication or cache fill --> RB[Regional cache B]
UA[Regional users A] -- local read --> RA
UB[Regional users B] -- local read --> RB
UA -. rare cross-region read on cache miss .-> P
UB -. rare cross-region read on cache miss .-> P
Consistency trade-offs the design introduces:
- Eventual consistency between the primary and each regional copy: a write is visible immediately at the primary, but a regional reader may see the pre-write value until the replication or refresh path catches up. The design should state a target replication lag, such as regional reads reflecting writes within a stated number of seconds, as an explicit, monitored number, not leave it undefined.
- Read-your-own-write expectations break unless handled specially: a user who just wrote something and immediately reads it back from their own region's cache may not see their own change. Common fixes are routing that user's next read to the primary for a short window, or a client-supplied version token the regional cache honors, meaning give me a result at least this fresh.
- Read latency guarantees for regional users hold for the steady-state, cache- or replica-hit path, but a cache miss still pays the full cross-region round trip. State the latency guarantee as a target hit ratio plus the resulting blended latency, rather than a claim that every single read is fast.
Worked example
Assume regional cache B currently achieves a steady-state hit rate of 92% against its frequently-read content, with local-hit latency in the tens of milliseconds and cross-region-miss latency several times higher, a qualitative, order-of-magnitude comparison, not a specific measured benchmark. Because the blended expected latency is dominated by the 92% local-hit path, the region's read latency guarantee can be stated and monitored as: at or below the local-hit latency for at least 92% of reads, with the miss path explicitly carved out and separately tracked, rather than promising one number for every read.
Trade-offs and pitfalls
A design that never states its replication lag target is not actually safer, it is just undocumented; eventual consistency without a number is a promise nobody can verify or alert on. Read-your-own-write bugs are the single most common user-visible symptom of this pattern, a user who appears to lose their own update; decide and document the fix, sticky routing to primary or version tokens, rather than discovering it from a bug report. A very high regional cache hit rate can hide a slowly growing miss rate, content churn outpacing the refresh path, until it suddenly shows up as a latency regression; monitor hit rate as its own alerting signal, not only aggregate latency.
Design an observability and A/B performance experimentation platform that allows safe testing of cost-saving optimizations. Describe how you would capture metrics, create cohorts, run statistical tests on latency and error metrics, and attribute cost changes to experiments.
Sample Answer
Frame the deliverable first: this platform must let an engineer ship a cost-saving change (a smaller instance type, a shorter cache TTL, a cheaper storage tier) and get back a statistically defensible answer to two questions: did latency or error rate regress, and how much money did the change actually save.
1. Metric capture
Every request emits a structured event at the edge (the API gateway or a lightweight capture layer) tagged with a stable user or session id, the experiment id and the cohort (variant) it was bucketed into, latency, HTTP status, and the resource consumption attributable to that request (compute time, bytes read or written, any downstream calls it triggered). Stream these events into a columnar analytics store partitioned by day and experiment id, so both the live dashboard and the offline statistics job read the same source of truth. p95 and p99 latency (the value below which 95% or 99% of requests complete) and error rate are computed per cohort per time window directly from this raw event stream, not from pre-aggregated averages, so the statistical test below can see the full distribution rather than a single summary number.
2. Cohort assignment
Bucket by a deterministic hash of a stable id (user id, or session id for anonymous traffic) into control and treatment, so the same entity lands in the same cohort for the life of the experiment (sticky bucketing). This avoids contaminating the comparison with entities that flip between arms mid-experiment.
3. Statistical testing
Latency is heavy-tailed, not normally distributed, so comparing means with a t-test (a test that compares two groups' averages and assumes the data is roughly bell-shaped) is the wrong tool: use a non-parametric test such as Mann-Whitney U (checks whether one group's values tend to run higher than the other's, without assuming any particular distribution shape) or bootstrap resampling (repeatedly resampling the observed data with replacement and recomputing the statistic each time, to see how much it naturally varies) on the percentile of interest to get a confidence interval on the p95 or p99 difference between cohorts. Error rate is a proportion, so a two-proportion z-test (compares two observed rates using their standard errors to judge whether the gap is likely real or just chance) or chi-squared test (compares observed counts across categories against what you'd expect if there were no real difference) is appropriate there. Set a minimum detectable effect (the smallest true difference the experiment needs to be able to reliably detect) and the required sample size before the experiment starts, and define guardrail metrics (error rate, p99 latency) that can auto-abort the experiment if they regress past a threshold, independent of whether the cost number looks good.
4. Cost attribution
Tag every unit of infrastructure spend the request touches (compute-seconds, storage bytes, egress) with the experiment id and cohort at capture time, the same way the latency event is tagged. At the end of the window, sum tagged spend per cohort and divide by cohort request count to get a cost-per-request for each arm; the saving is the control's cost-per-request minus the treatment's, multiplied by projected full-traffic volume. This is the same tagging discipline a chargeback system (a process that bills each team for the share of shared infrastructure cost it actually consumes) uses to attribute shared infrastructure cost to a team, just applied at experiment granularity instead of team granularity.
Worked example (illustrative numbers)
Control cohort: p95 latency 240ms, cost-per-request $0.00042. Treatment cohort (a smaller instance type): p95 latency 255ms, cost-per-request $0.00031. The cost saving is real and material, about 26% per request (($0.00042 minus $0.00031) divided by $0.00042), but the 15ms p95 regression (255ms minus 240ms) needs its own confidence interval; bootstrap resampling the raw per-request latencies gives an illustrative 95% confidence interval on that 15ms delta of roughly [9ms, 21ms]. Because that interval excludes zero, the regression is real rather than noise, and since the SLO guardrail (service level objective, the internal performance target the team holds itself to) is 250ms p95, the experiment fails the guardrail despite the cost win, and the treatment does not ship.
Trade-offs
The observability pipeline itself costs money, so once traffic is high enough that a 1 to 10 percent sample still gives statistical power, sample rather than log every request. Watch for cohort-imbalance effects, where the traffic mix shifts between the start and end of the window, since that can bias the cost comparison independent of the change itself.
What I would check
That cost tagging captures shared and downstream cost (a smaller instance that pushes more retries onto a downstream service is not actually cheaper), and that the experiment ran long enough to cover a full weekly cycle, so day-of-week traffic patterns do not skew either the latency or the cost comparison.
You must migrate 1 PB of archival data from S3 Standard to Glacier Deep Archive with unknown retrieval patterns but a compliance requirement for rare emergency access. Design a migration plan that minimizes monthly cost while preserving the ability to retrieve subsets quickly if needed. Include testing, cold-start retrieval simulation, and cost modeling.
Sample Answer
Framing
A petabyte (PB) is about 1,000,000 GB. The tricky part of this migration is not the bulk move itself, it is that "unknown retrieval patterns" plus "rare emergency access under a compliance requirement" means the data cannot be treated as truly cold. The plan needs to get almost all of it to the cheapest tier while keeping a documented, tested path back to any subset of it on short notice.
Tiering and migration strategy
- Before moving anything, build (or use an existing) manifest: an inventory of every object with its key, size, last-access timestamp, and content type. This is the map that makes "unknown retrieval patterns" less unknown, since even without access logs, object age, size, and naming convention are a decent proxy for what is likely to be requested.
- Migrate in waves using batch operations, not a single one-shot job: start with the oldest, largest, least-referenced prefixes first, and hold back anything flagged as recently touched or under a compliance hold for a later wave once its access pattern is better understood.
- Bundle small files before migrating. Deep Archive (the cheapest, slowest-restore AWS storage class, meant for data touched less than once a year) bills a per-object minimum of roughly 40 KB at standard rates regardless of the real file size, so a directory of many small files can cost far more than its raw byte count suggests. If the average object is well under 128 KB, I would tar or zip files within a prefix into larger archives before migrating, with the manifest pointing at (archive file, offset) instead of individual keys.
- Respect the minimum storage duration: Deep Archive charges a minimum retention period (180 days in AWS's case) even if an object is deleted or moved sooner, so this only pays off for data that is genuinely going to sit for a long time, which fits an archival compliance dataset.
Retrieval readiness for emergency access
- Deep Archive typically only offers slow restore tiers (many hours, sometimes a day or two), with no fast option. If the compliance requirement genuinely means "sometimes we need this back fast," I would keep a small, identified subset (from the manifest) in a warmer archival tier that does support a faster restore option, sized to whatever fraction of the data is plausibly an emergency target, and put the rest in Deep Archive.
- Every restore request goes through a documented runbook: who can request it, how the request is authorized (this is compliance data), and a status page showing restore progress, since the requester otherwise has no visibility into an hours-long wait.
Testing and cold-start retrieval simulation
- Before migrating the full petabyte, run a canary: migrate a representative 1% sample (stratified across object age, size, and prefix) to Deep Archive, then actually trigger restores against it on a schedule, not just once. Measure end-to-end time from restore request to a checksum-verified, readable object, not just a restore job marked complete.
- Simulate the true cold-start case deliberately: pick objects nobody has touched in the sample window and restore those, since the objects most likely to get tested informally are the ones people already remember, the opposite of what rare emergency access will actually look like.
- Test failure modes too: concurrent restore request limits, a restore result that expires before anyone downloads it, and a stale or incomplete manifest, not just cloud-side behavior.
Cost model
Using one basis, illustrative pricing of $0.023/GB-month for standard storage and $0.00099/GB-month for Deep Archive:
- Leaving everything in standard storage: 1,000,000 GB times $0.023 is roughly $23,000/month.
- Migrating to Deep Archive: 1,000,000 GB times $0.00099 is roughly $990/month.
- That is about $22,000/month saved, or roughly 96% off the standard-tier bill, before accounting for the small warm subset kept out for emergency access and the one-time migration request costs (transfer requests are billed per object, another reason to bundle small files first).
What I'd validate before calling it done
I would reconcile the modeled monthly figure against the actual first month's bill, since estimates and real bills diverge, often because of small-object overhead or more data than expected landing in the warm tier. I would re-run the restore drill on a schedule (quarterly, say) so the emergency access path does not silently rot between the one time it was tested and the one time it is actually needed.
You have a microservice that sends events to a downstream system at high QPS. Network egress costs are growing quickly. Propose three engineering approaches to reduce egress costs and explain the cost versus latency trade-off for each.
Sample Answer
Framing
Egress cost is what a cloud provider charges for data leaving its network, typically billed per GB and often the least visible line item on a bill because it scales with traffic rather than with anything you provision directly. At high QPS (queries per second, meaning a large number of requests per second), even a small per-event payload adds up fast, so the fix has to attack either the number of bytes sent, the number of separate network calls made, or the network path those bytes travel.
Three approaches
- Compress each event payload (gzip or zstd) before it goes over the wire.
- Batch many events into fewer, larger HTTP or gRPC calls instead of sending one call per event.
- Route the traffic over a private network path (VPC, virtual private cloud, peering; PrivateLink, a cloud-provider service that connects two private networks without touching the public internet; or colocating the downstream system in the same region) instead of the public internet.
Worked example (one basis: illustrative egress rate of $0.09 per GB)
Say the service sends 5,000 events/sec, 2 KB each (JSON). That is 10 MB/sec, or about 844 GB/day. At $0.09/GB that is roughly $76/day just for the raw bytes, before any HTTP header overhead.
- Compression: JSON compresses well, often 4 to 6x. At 5x, 844 GB/day drops to about 169 GB/day, or roughly $15/day, a savings of about $61/day. Trade-off: compression and decompression cost CPU cycles on both ends, extra compute spend rather than extra latency for a user, since this is server-to-server. That trade almost always favors compression for text payloads.
- Batching: if each request carries roughly 500 bytes of HTTP/TLS framing overhead on top of the 2 KB payload, sending one request per event wastes about 20% of every call on overhead. Batching 20 events per call cuts that per-event overhead by roughly 20x. Trade-off: batching trades latency for efficiency. Events sit in a buffer until the batch window closes (for example, 100ms or N events), so anything downstream that needs near-real-time delivery pays that delay.
- Private network path: routing through VPC peering or a PrivateLink endpoint instead of the public internet avoids internet egress pricing in most clouds, sometimes dropping the rate close to zero for intra-region traffic. Trade-off: this needs upfront infrastructure work and only helps if the destination can live in or be reached through your private network. Unlike the other two, it usually improves latency as well, since the network path gets shorter, so the real cost is one-time engineering effort rather than an ongoing latency tax.
How I'd decide
Start with compression since it needs no downstream changes and no infrastructure work, just a client-side encoder. Layer batching on top if the downstream system tolerates a delivery delay, since it stacks with compression (fewer, smaller calls). Only invest in private network routing if the destination is under your control or a cloud-native managed service, since that is the biggest one-time lift but also removes the cost driver at its source instead of just shrinking it.
Unlock Full Question Bank
Get access to all Performance Cost Optimization & Resource Efficiency interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.