Spot Instances in Practice: What the 90% Discount Requires, and Designing for Interruption

5 min read

There are three axes for cutting EC2 costs: commitments via RIs and Savings Plans, architecture via Graviton, and this post’s subject, Spot. The conclusion up front: Spot is a contract that grants up to 90% off on-demand (40–70% in realistic practice) with no commitment, limited to workloads that can absorb interruption — and the deciding question is not price but “is it acceptable for this to vanish after a 2-minute notice?” Not using Spot where the answer is yes is leaving money on the table; using it where the answer is no is scheduling an outage. Prices are for us-east-1.

Side-by-side comparison #

AspectOn-demandSpot
DiscountNone (baseline)Up to 90%, varies by pool
CommitmentNoneNone
InterruptionNoneReclaimable after 2-minute notice
Capacity assuranceHighNone (requests can go unfilled)
SLA-bound, stability-critical workloadsSuitableUnsuitable
Batch, CI, stateless scale-outWorks (expensive)Optimal
CombinationTarget of RIs and SPsSeparate market; handles the variable part

The substance of the contract: spare capacity, cheap, and returnable #

Spot sells AWS’s spare EC2 capacity at market prices. Prices move gently per pool (instance type × AZ) with supply and demand, generally landing at 10–30% of on-demand. The trade-off is twofold: when AWS needs the capacity back, the instance is reclaimed after a 2-minute notice, and if a pool has no capacity, the request may simply go unfilled.

Interruption is part of the contract, not an exception. The notice arrives via instance metadata (IMDS) and EventBridge, and a rebalance recommendation often arrives earlier still, buying time to pre-launch replacements and drain work. The skill of running Spot is therefore not picking the cheapest pool — it is automating the routine of wrapping up and leaving within two minutes.

Where it belongs: interruption tolerance is the bar #

Good fits keep state outside and retry naturally: CI build and test runners, batch and data processing (checkpointed), the stateless scale-out portion of services on container orchestrators, rendering and simulation, development environments. On Kubernetes or ECS, an interruption is absorbed as “one node gone,” which is why the fit is especially clean.

Poor fits hold state inside or carry high interruption cost: databases, single-instance services, long jobs without checkpoints, and commercially licensed software tied to an instance. The accurate rule is not “no Spot in production” but “no Spot without interruption tolerance.” The scale-out portion of a production service that tolerates interruption is legitimate Spot territory.

The standard production shape is a mix: lock the floor with on-demand plus commitments, and fill the variable part above it with Spot. Auto Scaling groups support this natively with mixed instances policies, including a percentage split between on-demand and Spot.

Engineering the interruption rate down: diversification and allocation #

Interruption frequency is a design output, not luck.

  • Instance diversification: each pool (type × AZ) has its own capacity situation, so the wider the set of acceptable types, the higher the odds of running in a deep pool. Not “m7i.large only” but several generations and sizes across m, c, and r — the instance family comparison still guides the choice, just applied broadly.
  • Allocation strategy: price-capacity-optimized: the current recommended default. It picks pools that are cheap and deep rather than merely cheapest, and interruption rates drop visibly versus the lowest-price strategy, which piles into shallow pools and pays the savings back in interruptions.
  • Fargate Spot for containers: Fargate tasks have a Spot tier too, at roughly 70% off. It lacks EC2 Spot’s type-diversification lever, so it suits short batch tasks and interruption-tolerant services.

One pricing note: Spot discounts and RI/SP commitments do not stack. Commitments discount on-demand usage and Spot is a separate market, so size commitment coverage to the floor and exclude Spot usage from that math.

Decision order #

  1. Write the interruption scenario first: what happens if this workload’s instance vanishes after a 2-minute notice? “It retries and finishes” makes it a Spot candidate; “data loss or an outage” rules it out.
  2. Move state outside: work queues, checkpoints, and external storage widen the Spot-eligible area — adopting Spot tends to push the architecture somewhere healthier anyway.
  3. Configure diversification and allocation: widen the type set, set price-capacity-optimized, and treat the notice and rebalance handlers (automated draining) as part of the same unit of work.
  4. Split floor and variable: floor on on-demand plus commitments, variable on Spot, expressed in the Auto Scaling mixed policy.
  5. Watch interruption rates and adjust: drop chronically interrupted pools from the candidate set, and verify on-demand fallback works when Spot fill rates sag. Spot is operated with observation, not set and forgotten.

Summary #

  • Spot grants up to 90% off with no commitment in exchange for 2-minute-notice reclamation. The bar is interruption tolerance, not price.
  • CI, batch, and stateless scale-out are optimal; databases and uncheckpointed long jobs are out. The criterion is where state lives, not whether it is production.
  • Interruption rates are engineered down: type diversification, price-capacity-optimized allocation, and automated notice handling are the standard trio.
  • The standard shape is a mix — floor locked with on-demand plus RIs/SPs, variable filled by Spot, with Spot excluded from commitment coverage math.
  • Containers get Fargate Spot (~70% off). With this, the three cost axes — commitments, Graviton, Spot — are complete.
X