Cost Optimization at Scale¶
Small workloads can eyeball their AWS bill. At scale — hundreds of instances, many accounts — cost optimization becomes systematic: committing to predictable usage for a discount, using interruptible capacity where possible, and continuously rightsizing based on real utilization data.
Savings Plans vs. Reserved Instances vs. Spot¶
| Flexibility | Discount vs. on-demand | Commitment | |
|---|---|---|---|
| On-Demand | Full | None (baseline) | None |
| Savings Plans | Compute or EC2-instance-family scoped | Substantial | 1 or 3 years, $/hour commitment |
| Reserved Instances | Locked to instance family/region (Standard) or flexible (Convertible) | Substantial, similar to Savings Plans | 1 or 3 years |
| Spot Instances | Interruptible, any workload tolerant of termination | Largest | None — priced by market, can be reclaimed |
Compute Savings Plans are the most flexible commitment — they apply across EC2, Fargate, and Lambda regardless of instance family or region, in exchange for a slightly lower discount than instance-family- locked EC2 Savings Plans or Standard RIs.
aws ce get-savings-plans-purchase-recommendation \
--savings-plans-type COMPUTE_SP \
--term-in-years ONE_YEAR \
--payment-option NO_UPFRONT \
--lookback-period-in-days SIXTY_DAYS
aws savingsplans create-savings-plan \
--savings-plan-offering-id offering-abc123 \
--commitment 10.00
Cost Explorer's get-savings-plans-purchase-recommendation analyzes
your last 30/60 days of usage and recommends a commitment level that
covers steady-state usage without over-committing to capacity you
might not use.
Spot for interruption-tolerant workloads¶
{
"IamFleetRole": "arn:aws:iam::123456789012:role/aws-ec2-spot-fleet-role",
"AllocationStrategy": "capacityOptimized",
"TargetCapacity": 20,
"LaunchSpecifications": [
{ "InstanceType": "m5.large", "SubnetId": "subnet-0aaa111" },
{ "InstanceType": "m5a.large", "SubnetId": "subnet-0aaa111" },
{ "InstanceType": "m6i.large", "SubnetId": "subnet-0aaa111" }
]
}
capacityOptimized allocation picks spot pools with the deepest
available capacity (lowest interruption risk) rather than the cheapest
price — for batch jobs and stateless workers, mixing several instance
types/families widens the pool AWS can draw from and reduces
simultaneous interruption risk.
Rightsizing with Compute Optimizer¶
aws compute-optimizer get-ec2-instance-recommendations \
--instance-arns arn:aws:ec2:us-east-1:123456789012:instance/i-0abc123def456
# {
# "instanceRecommendations": [{
# "currentInstanceType": "m5.2xlarge",
# "finding": "OVER_PROVISIONED",
# "recommendationOptions": [{ "instanceType": "m5.large", "performanceRisk": 1.2 }]
# }]
# }
Compute Optimizer analyzes 14+ days of CloudWatch utilization and flags
instances as OVER_PROVISIONED, UNDER_PROVISIONED, or
OPTIMIZED — turning "does this need to be this big" from a guess into
a data-backed recommendation across an entire fleet at once.
Cost allocation and anomaly detection¶
# Tag-based cost tracking — activate a cost allocation tag
aws ce update-cost-allocation-tags-status \
--cost-allocation-tags-status TagKey=team,Status=Active
aws ce get-cost-and-usage \
--time-period Start=2026-08-01,End=2026-08-25 \
--granularity DAILY \
--metrics UnblendedCost \
--group-by Type=TAG,Key=team
aws ce create-anomaly-monitor \
--anomaly-monitor '{"MonitorName":"prod-monitor","MonitorType":"DIMENSIONAL","MonitorDimension":"SERVICE"}'
Cost Anomaly Detection uses ML on historical spend patterns to flag unusual spikes per service/account automatically, rather than someone noticing a surprise on the monthly bill weeks later.
S3 storage class tiering¶
aws s3api put-bucket-lifecycle-configuration \
--bucket training-datalake-raw \
--lifecycle-configuration '{
"Rules": [{
"ID": "tier-old-data",
"Status": "Enabled",
"Filter": { "Prefix": "orders/" },
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER" }
]
}]
}'
Gotchas¶
- Savings Plans commit to a dollar-per-hour spend, not specific resources — under-forecasting usage wastes the commitment (you pay it whether or not you use it); over-committing based on a temporary spike locks in cost for months or years.
- Spot capacity can disappear entirely for a given instance type/AZ combination — a fleet requesting only one instance type in one AZ has no fallback; diversify across types and AZs as shown above.
- Compute Optimizer needs enrollment and 14+ days of data — a freshly launched account or instance won't have recommendations yet; it isn't real-time.
- Storage class transitions aren't free — Glacier retrieval has its own cost and multi-hour to multi-day latency depending on retrieval tier; lifecycle rules on frequently-accessed data can backfire into higher total cost from repeated retrievals.
- Tag-based cost allocation only tracks resources tagged after the tag is activated — retroactive tagging doesn't retroactively populate Cost Explorer's historical breakdown.
Cheat sheet¶
| Task | Command |
|---|---|
| Get Savings Plan recommendation | aws ce get-savings-plans-purchase-recommendation |
| Purchase a Savings Plan | aws savingsplans create-savings-plan |
| Request diversified spot capacity | aws ec2 request-spot-fleet |
| Get rightsizing recommendations | aws compute-optimizer get-ec2-instance-recommendations |
| Group costs by tag | aws ce get-cost-and-usage --group-by Type=TAG |
| Detect spend anomalies | aws ce create-anomaly-monitor |
| Tier S3 storage automatically | aws s3api put-bucket-lifecycle-configuration |
How It Actually Works¶
At scale, cost optimization is fundamentally about exploiting how each service's billing meter actually works, not just "using less." Spot Instances are spare EC2 capacity AWS's own internal capacity-management system has determined it doesn't currently need for On-Demand/Reserved commitments — pricing floats based on real-time supply and demand per instance pool (instance type + AZ), and the two-minute interruption notice you get before reclamation exists because AWS's capacity system needs that resource back for a higher-priority (On-Demand/Reserved) request, not because of anything you did; this is why Spot strategy at scale means diversifying across many instance-pool combinations (so losing one pool's capacity doesn't take down your whole fleet) rather than picking the single cheapest option.
Savings Plans work through the billing engine's rating step (module 09, Level 2) matching your committed dollar-per-hour rate against any eligible usage first, before falling back to on-demand rates for the remainder — at fleet scale, this means Savings Plans should be sized against your aggregate, sustained baseline usage across the whole organization (often via a payer account applying discounts across linked accounts), because the discount-matching happens organization-wide during the same consolidated billing rating pass, not account-by-account.
S3 Intelligent-Tiering at scale works by S3 itself monitoring per-object access patterns and automatically moving objects between access tiers based on observed (not predicted) usage — this is a real, continuous background process S3 runs against your bucket's actual request logs internally, which is why it has no retrieval fees between the frequent and infrequent tiers (unlike manually choosing Standard-IA) but does carry a small per-object monitoring fee: you're paying for that continuous tier-decision computation instead of doing the tiering analysis yourself.
Exercise¶
Using aws compute-optimizer get-ec2-instance-recommendations (or the
console if CLI access isn't enrolled), find one instance flagged
OVER_PROVISIONED in a test account, and write out the exact
aws ec2 modify-instance-attribute command you'd run to resize it to
the recommended type during a maintenance window.