Cloud Compute Options and Trade-offs Questions
Choosing among compute abstractions independent of provider: virtual machines, containers, managed container services, serverless functions, and bare metal. Covers the cost, control, cold-start, scaling, and operational trade-offs of each model; how to pick an instance family or hardware accelerator (general-purpose, compute-optimized, memory-optimized, GPU, TPU) and a purchasing model (on-demand, reserved, spot); and how workload characteristics (latency, statefulness, burstiness) drive the decision. Managed-versus-self-managed reasoning lives here.
List the trade-offs between serverless (FaaS) and container-based deployments for compute workloads. For a latency-sensitive public API that needs sub-100ms cold starts, which approach would you recommend and why? Consider cost, operational overhead, scaling characteristics, and vendor lock-in.
Sample Answer
Direct answer
For a public API that must hit sub-100ms cold starts, recommend containers running on an autoscaled fleet with an always-warm minimum, over pure serverless functions (function-as-a-service, or FaaS: compute you don't provision servers for, billed per invocation), because a 100ms budget leaves almost no room for a cold-start penalty that FaaS platforms can mitigate but cannot fully eliminate. If the team commits to serverless anyway, provisioned or pre-warmed concurrency becomes mandatory at that latency bar, not an optional extra.
Evaluate suitability before mitigating
Before reaching for cold-start fixes, check whether serverless is even the right fit for this latency target. Ask whether the 100ms figure is a p50, a p95, or a hard ceiling on every request: a 100ms p95 with occasional 300ms cold outliers may be tolerable for some APIs, but a 100ms ceiling on every single request is not achievable on FaaS without paying to keep enough capacity permanently warm, at which point you have effectively re-invented a container. Only once that check is done does it make sense to move to mitigation.
Trade-offs
| Dimension | Serverless (FaaS) | Containers |
|---|---|---|
| Cost at low, spiky traffic | Near zero when idle | Pay for the always-on floor regardless of traffic |
| Cost at high, sustained traffic | Per-invocation billing can exceed an equivalent container fleet's cost | Amortizes well |
| Cold start | Present, mitigable but not eliminable | None once the fleet is warm |
| Scaling granularity | Very fine, near-instant concurrency | Coarser, bound by autoscaler reaction time |
| Vendor lock-in | Highest in the event-trigger and concurrency-configuration glue | Lower; a container image runs anywhere |
| Local debugging | Hard to reproduce the platform's exact execution model locally | A pulled image runs byte-for-byte identical to production |
A simple structuring device for a stateless HTTP microservice: three factors usually decide it. Traffic shape (steady versus bursty or idle-heavy), latency sensitivity (can the tail tolerate an occasional cold-start spike), and the team's operational appetite for managing a fleet versus handing that off.
Cold-start mitigation, for the hardest target
For a very aggressive latency target, mitigation has to go beyond "turn on provisioned concurrency." Keep the deployment bundle small: tree-shake unused code and avoid bundling an entire client library when only one call is used, since a larger package with more dependencies to load makes runtime bootstrap slower. Avoid initializing heavyweight clients (database drivers, connection pools) at module load time if they can be created lazily on first use, so the fixed cost of a cold start is smaller. Reuse anything safe to cache across invocations within the same warm execution environment, such as a live database connection or a compiled regular expression, rather than redoing that work every time. None of this replaces provisioned concurrency; it makes provisioned concurrency's warm baseline actually fast once it's warm, and shrinks the penalty on the rare cold invocation that still slips through.
The local-debugging cost, from an operations perspective
Local debugging is genuinely harder for serverless, because a local development environment can't fully reproduce the platform's execution model: cold-start behavior, the exact shape of the triggering event, and the runtime's network and identity context. An engineer debugging a production-only serverless issue at an inconvenient hour often can't reproduce it locally and has to rely on remote logs and traces alone. A container image, by contrast, can be pulled and run locally byte-for-byte identical to what's running in production, which is a real advantage when something is failing and every minute matters.
Worked example
For the sub-100ms public API, recommend a small containerized service with a minimum of two to three replicas always running, so nothing ever scales to zero and nothing ever cold-starts. Autoscale on CPU or requests-per-second with enough headroom that scale-out finishes before the added replicas are actually needed. If traffic is extremely spiky and mostly idle, revisit the comparison on total monthly cost, not intuition: once you price continuous provisioned concurrency to protect the latency target, that cost starts to look a lot like renting a small container fleet anyway, so the "serverless is cheaper" assumption doesn't automatically hold.
Trade-offs and pitfalls
The dominant wrong turn is picking FaaS for a hard latency service-level agreement and discovering cold starts only in production. Load-test cold-start behavior explicitly, with a burst of genuinely cold invocations rather than steady warm traffic, before committing either way. On vendor lock-in, keep the actual handler logic as plain, portable functions with the platform's event-trigger wiring as a thin adapter layer, so a future move from serverless to containers is a rewrite of the edges, not the core.
You have a small daily ETL job that processes 50,000 records and runs for about 15 minutes. Which compute option would you choose among a VM, a managed batch service, a container on Kubernetes, and a serverless function, and why? Address cost, operational effort, scalability, and reliability.
Sample Answer
Direct answer
For a small daily extract-transform-load job processing 50,000 records in about 15 minutes, recommend a managed batch service, a platform purpose-built for running scheduled or triggered jobs to completion without managing servers or a cluster, or, if none fits the existing stack, a serverless function with an execution-time limit that comfortably covers the 15-minute run. Both avoid paying for or operating standing infrastructure for a job that runs briefly once a day, which is the dominant consideration at this scale.
Comparing all four options
Virtual machine. Cost: you pay for the instance continuously unless you build explicit start-and-stop scheduling around the 15-minute window, which is wasteful and adds its own machinery. Operational effort: you own operating-system patching and the scheduling logic yourself. Scalability: a single virtual machine doesn't scale within the job; you'd resize it manually if the record count grew. Reliability: if the instance or the job process dies mid-run, you need your own retry and monitoring logic, since nothing manages that for you. This option is overkill for a job this size.
Managed batch service. Cost: you pay only for the compute-minutes the job actually runs, similar economics to serverless but designed for job-shaped workloads with a defined start and completion rather than request-and-response traffic. Operational effort: the lowest of the four, since the platform handles scheduling, retry on failure, and resource provisioning for the job's duration. Scalability: typically absorbs a growing record count by scaling the job's resource allocation without a re-architecture. Reliability: built-in retry-on-failure and completion tracking are usually native to the platform, which fits a job that needs to reliably finish, not just start. This is the strongest fit here.
Container on Kubernetes (Kubernetes automates deploying, scaling, and scheduling containers across a cluster of machines). Cost: close to free incrementally if a cluster already runs other workloads; a large fixed cost if a cluster would need to be stood up just for this one job. Operational effort: low if the cluster already exists and is operated by someone else on the team, high if cluster operations would be built from scratch for this. Scalability: scales cleanly by adjusting the job's resource requests. Reliability: Kubernetes' native job and retry semantics handle re-running a failed job. This is a good fit only if the cluster already exists for other reasons.
Serverless function. Cost: pay only for actual execution time, nothing when idle, which fits a job running once a day for 15 minutes very well, as long as the platform's maximum execution duration comfortably covers that with margin. Operational effort: the lowest, with no infrastructure to manage at all. Scalability: fine for a fixed daily record count, but if that count grew enough to push against the platform's execution-time or memory ceiling, the job would need to be re-architected, for example split into parallel chunks, rather than simply resized, which a managed batch service or a cluster job would handle more gracefully. Reliability: depends on the platform's retry-on-failure behavior for scheduled invocations, which is usually available but should be explicitly configured, not assumed.
Recommendation
Choose a managed batch service if the cloud provider offers one that fits the existing tooling, since it's purpose-built for exactly this job shape: bounded duration, retry-to-completion, no idle cost. Choose serverless instead if a managed batch service isn't available or convenient and the job comfortably fits within the platform's execution-time limits with room to grow. Reserve the Kubernetes-job option for when a cluster already exists for other workloads, and avoid the virtual machine entirely, since none of its trade-offs favor it at this scale.
Trade-offs and pitfalls
A common pitfall is defaulting to "we already have a Kubernetes cluster, just run it there" without checking whether the job's growth trajectory, in record count or run time, will eventually create resource contention with other workloads on a busy shared cluster; a small extra job can quietly become a noisy neighbor. A second pitfall is putting the job on serverless without checking the platform's maximum execution duration against the job's real worst-case run time; 15 minutes today doesn't guarantee 15 minutes forever as data volume grows, and the job can get silently killed mid-run once it passes the limit, rather than failing loudly with a clear cause.
Immutable infrastructure (e.g., golden images or container images) and mutable instances take very different approaches to keeping servers up to date. Compare their trade-offs, and how each affects patching, scaling, deployments, and operational complexity for a service that requires high availability.
Sample Answer
Direct answer
Immutable infrastructure treats a server as disposable: you bake a fixed golden image or container image with the OS, runtime, and application already installed, and any change (a patch, a config edit, a new release) is deployed by building a new image and replacing running instances, never by editing a live box. Mutable infrastructure keeps long-lived instances and updates them in place (package managers, configuration-management tools, patches applied over a remote shell). For a service that requires high availability, immutable infrastructure is the better default, because it makes every deployed unit provably identical, which is what makes rolling upgrades and rollback safe. The cost is a heavier build pipeline and less ability to just log in and fix something quickly.
How the two approaches actually differ
| Dimension | Immutable (golden image / container image) | Mutable (in-place updates) |
|---|---|---|
| Patching | Rebuild the image with the patched base layer, redeploy; every replica ends up bit-identical | Apply the patch to running hosts via config management or manual commands; risk of partial or divergent patch state across the fleet |
| Scaling out | A new instance boots directly from the already-current image; correct from its first health check | A new instance clones a base image, then a configuration run converges it to current state; slower, and can be wrong if convergence hasn't finished before it takes traffic |
| Deployments | Replace old instances with new-image instances (rolling replacement or blue-green); rollback is redeploying the previous image | Mutate the fleet in place; requires careful batching to avoid a half-updated fleet mid-rollout |
| Operational complexity | Needs an image build, scan, and registry pipeline, plus version discipline | Needs configuration-management tooling and drift detection/auditing, plus tightly controlled remote-access security |
For high availability specifically, immutable infrastructure buys guaranteed fleet homogeneity (a health check passing on one instance means it will pass on all of them, since they are the same bytes), and fast, safe rollback (swap the image tag back). A mutable fleet can reach similar guarantees, but only with rigorous idempotent configuration management and drift auditing, and "it works because we ran the playbook" is weaker evidence than "it works because it's the same image we already tested."
Worked example
A team runs a stateless, high-availability API behind a load balancer with a minimum of 3 and a maximum of 12 instances. Immutable path: continuous integration builds image vX, runs smoke tests, publishes it to a registry, and the autoscaling launch template points at vX. A security patch (say, a library CVE fix) means rebuilding the base layer into vX+1 and doing a rolling replacement with zero instances allowed to go unavailable at once, always keeping at least 3 healthy. The time to fully roll out the patch is bound mostly by the image build time plus one health-checked rolling cycle, not by touching 12 live hosts individually. Mutable path: the same patch is pushed via configuration management to 12 running instances. Patching all 12 at once risks dropping below the 3-instance availability floor if several restart together, so the team batches in groups of 3, waiting for each batch to converge and pass health checks before continuing. Both paths can land at the same wall-clock outcome, but immutable's advantage is that "did it work" is answered once, at image build and test time, instead of by 12 separate convergence proofs that could each silently fail.
Trade-offs and pitfalls
A common wrong turn is treating a container image as automatically immutable while still shelling into the live container to "fix something quick." That reintroduces mutable-instance drift inside a model whose entire value proposition is that no one does that. Immutable infrastructure also needs somewhere to put state, since local writes vanish the moment an instance is replaced; a stateful workload retrofitted onto immutable instances without externalizing its state to a managed database or object store will quietly lose data on every deploy. On the mutable side, the classic failure is configuration drift accumulating over time from unmanaged manual fixes, discovered only when an incident happens on the one host nobody actually patched. Recommend immutable as the default for high-availability, largely stateless services, and reserve mutable instances (or immutable compute with an attached persistent volume) for cases where image rebuild time is genuinely prohibitive relative to deploy frequency, or where the workload is intrinsically stateful and better run as a managed service.
Cold starts in a serverless function are hurting user experience. Define concrete metrics and an experiment design to measure cold-start frequency and its latency impact in production, and describe how you'd turn that data into SLOs with automated alerting.
Sample Answer
Direct answer
Cold starts need two distinct metrics tracked separately, not blended into one number: the cold-start rate (what fraction of invocations pay the cold-start penalty) and the cold-start latency itself as its own distribution, separate from the warm-path latency distribution. Blending them into a single combined latency percentile hides exactly the tail behavior you're trying to catch, since a small cold-start rate can still produce a user-visible tail even when it barely moves an average.
Structured elaboration
Concrete metrics to define:
cold_start_rate = cold_invocations / total_invocations, tracked as a rolling rate (e.g., per 5-minute window), not a single aggregate over a long period, since it can spike sharply after a deploy or a traffic drop that lets instances scale to zero.cold_start_latency_p50 / p95 / p99(a percentile is the value below which that percentage of measurements fall; p95 latency is the number 95% of requests are faster than), computed only over invocations flagged as cold, kept as its own distribution rather than folded into the overall latency histogram.warm_latency_p50 / p95 / p99, the same percentiles computed only over warm invocations, so you have a clean baseline to compare against.- Whether an invocation was cold is usually available directly from the platform's own execution metadata (an explicit cold-start flag or an init-duration field); if the platform doesn't expose one directly, a reasonable proxy is flagging any invocation whose total duration exceeds the warm p99 by a wide margin, though a direct platform signal is always preferable to a proxy.
Experiment design to measure this in production:
- Instrument every invocation to tag itself cold or warm at the point of execution (using the platform's own signal), and emit that tag alongside the latency measurement, rather than trying to infer it after the fact from aggregate statistics.
- Deliberately exercise both paths with synthetic canary traffic: a steady trickle of low-frequency canary invocations (spaced far enough apart to guarantee the platform has scaled the function down and the next canary invocation is cold) alongside the organic traffic that mostly hits warm instances, giving a controlled, comparable cold-start sample even during periods of naturally low organic traffic.
- Correlate cold-start rate against concurrency and deploy events specifically, since both a fresh deploy (which invalidates warm instances) and a period of low traffic (which lets the platform scale to zero) are the two most common causes of a cold-start spike, and knowing which one caused a given spike changes the fix.
Worked example
Say a rolling 24-hour window logs 250,000 invocations, of which 2,000 are flagged cold:
cold_start_rate=250,0002,000=0.008=0.8%If the warm p95 latency is 45ms and the cold p95 latency is 620ms, the expected added latency contributed by cold starts, averaged across all invocations (by linearity of expectation, which holds even though percentiles themselves don't blend this way), is:
0.008×(620ms−45ms)=4.6msThat 4.6ms system-wide average looks negligible, and an SLO (service-level objective: a specific, measurable target for how the service should perform) written only against an overall blended p95 would likely never trip on it. But the 0.8% of users who actually hit a cold start are experiencing roughly 14 times the warm latency, a real, user-visible regression that the blended metric is specifically designed to hide. This is the case for the two-metric SLO structure below.
Turning this into SLOs with automated alerting: define two separate service-level objectives, not one, for example "cold-start rate stays below 1% over a rolling hour" and "cold p95 latency stays below 800ms," each with its own error-budget burn-rate alert (an error budget is the amount of SLO-violating behavior you're allowed before you've broken the target; a fast-burn alert fires if the rate spikes sharply after a deploy, a slow-burn alert if it creeps up gradually as traffic patterns shift). Alerting on the underlying rate and the cold-path latency separately catches a regression in either dimension that a single blended threshold would miss.
Trade-offs and pitfalls
- The single biggest pitfall is exactly the one this answer opened with: averaging cold and warm latency together into one number. It's mathematically valid for an expectation (as shown above) but not for a percentile, and teams that alert on a blended p95 routinely miss cold-start regressions until users complain.
- Canary-based synthetic cold-start measurement has to be tuned carefully: too frequent, and the canary itself keeps the function warm, defeating the purpose; too infrequent, and you don't get enough samples to trust the resulting percentile.
- Cold-start rate alone doesn't tell you the fix. A rate spike right after a deploy points at the deploy invalidating warm instances (a config or provisioned-concurrency issue); a rate spike with no recent deploy points at low traffic letting the platform scale down, which may call for a small provisioned-concurrency floor instead of a code change.
Compare cost for two deployment options given this workload: 1,000,000 requests per day with a 1-hour peak at 3,000 requests per second, average execution time 200ms, and 512MB memory per serverless invocation. The alternative is a managed container platform running 3 replicas sized at 0.5 vCPU and 1GB memory each behind a load balancer. Walk through how you'd estimate monthly cost, what additional operational costs to account for, and what non-price factors would influence the final recommendation.
Sample Answer
Direct answer
Before running any numbers, the two traffic figures given don't reconcile: a full hour sustained at 3,000 requests per second is 10.8 million requests, almost eleven times the stated 1,000,000 requests/day total. In a real estimate that's the first thing to flag back to whoever supplied the numbers, since the answer changes by an order of magnitude depending on which figure is authoritative. To give a usable answer anyway, I'll use the 1,000,000/day total (the number that actually drives billed cost for both options) for the cost estimate, and treat "3,000 requests/second for an hour" as the capacity target the infrastructure must survive, which is a separate, non-price question. On the cost math alone, the serverless option comes out cheaper here (about $56/month versus about $70/month for the container option), but the container option as specified is very likely undersized for the stated peak, which matters more than the 20% cost gap.
Structured elaboration
Serverless (function-as-a-service, FaaS) cost model: billed per invocation plus per GB-second of memory times duration.
monthly GB-seconds=(requests/day×30)×(memory GB×duration s)Using 1,000,000 requests/day, 512MB (0.5GB), 200ms, and current public list pricing for a major FaaS platform ($0.0000166667/GB-second, $0.20 per million requests) as a concrete, verifiable reference point:
- Monthly GB-seconds: 1,000,000×30×0.5×0.2=3,000,000
- Compute cost: 3,000,000×0.0000166667≈$50.00
- Request cost: 30,000,000/1,000,000×$0.20=$6.00
- Total: about $56/month
Managed container cost model: billed per vCPU-hour and GB-hour for whatever is provisioned, whether it's busy or not.
Using the given 3 replicas at 0.5 vCPU / 1GB, run continuously (a fixed fleet doesn't turn itself off), and current public list pricing for a comparable managed-container-per-task platform ($0.04048/vCPU-hour, $0.004445/GB-hour):
- vCPU-hours/month: 3×0.5×24×30=1,080; cost ≈$43.72
- GB-hours/month: 3×1×24×30=2,160; cost ≈$9.60
- Plus a load balancer in front of the replicas, roughly $16/month baseline
- Total: about $69.32/month
Additional operational costs neither number above includes: structured logging and tracing ingestion (30 million invocations a month generates a lot of log volume, and per-GB log-ingestion pricing on an observability platform can rival the compute bill if every invocation logs verbosely); a NAT gateway (a managed component that lets resources without a public IP address reach the internet) if the containers sit in a private subnet (a network segment with no direct path to the public internet) and call external services (hourly plus per-GB-processed charges that are easy to forget when only pricing compute); container image registry storage and CI/CD minutes; and, on the serverless side, provisioned concurrency if cold starts turn out to be unacceptable, which keeps a set number of execution environments pre-initialized and adds a standing cost on top of the per-invocation price, partially eroding the serverless cost advantage (reserved concurrency is a different, unrelated lever: it caps and guarantees a slice of the account's concurrency limit for this function specifically, but it does not pre-warm anything, does not address cold starts, and costs nothing extra beyond the same per-invocation and duration charges already priced above).
Worked example: is the container fleet even sized correctly for the peak
Taking the 3,000 requests/second peak literally as a capacity requirement (regardless of which daily total is right): by Little's law (a queueing-theory identity: the average number of things in progress at once equals the rate they arrive times how long each one takes to finish), concurrent in-flight requests needed is 3,000×0.200s=600. Spread across 3 replicas that's 200 concurrent requests per replica, on only 0.5 vCPU each. That's plausible only if the workload is I/O-bound (mostly waiting on a downstream call, so one core can juggle many concurrent connections on an async runtime) and implausible if it's CPU-bound (200 concurrent CPU-bound requests cannot be served by half a core no matter the runtime). The question doesn't say which, and that single fact changes the real answer more than the raw cost comparison does: if CPU-bound, the "3 replicas" figure is a floor that must autoscale well beyond 3 during the peak hour, which raises the container bill above the $69.32 estimate above and could flip the recommendation either way depending on how much the peak fleet actually needs to grow.
Trade-offs and pitfalls
- Recommendation: given the total volume is modest (1,000,000/day) and there's a well-defined 1-hour peak against an implied low background rate the rest of the day, that traffic shape is exactly what per-invocation billing is suited for. I'd recommend serverless, on the condition that the team checks headroom on the platform's concurrency quota ahead of the peak. AWS Lambda's default regional concurrent-executions quota, for example, is 1,000, which comfortably covers the 600 concurrent executions this peak requires on its own, but that quota is shared across every function running in the same account and region, so a burst in an unrelated function during the same window can still exhaust it, and a newly created account can start with a lower, usage-scaled quota that the provider raises automatically over time. The team should confirm current utilization against that shared ceiling rather than assume 600 is automatically safe, and accept a bounded amount of cold-start latency risk, mitigated with a small amount of provisioned concurrency if the 200ms average execution time makes cold starts user-visible.
- What would flip it: if the workload is genuinely CPU-bound at that concurrency, the container option's real cost (after the autoscaling correction above) could exceed the naive estimate enough to erase the serverless price advantage, and control over the runtime (custom system dependencies, long-lived connections to a downstream database) would tip the decision toward containers regardless of price.
- The bigger pitfall in this whole exercise: computing confidently from numbers that don't agree with each other. A senior engineer reconciling a stakeholder's traffic estimate before committing budget to it is the actual skill being tested here, not producing a single dollar figure.
Unlock Full Question Bank
Get access to all 17 Cloud Compute Options and Trade-offs interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.