Rightsizing, Savings Plans, Spot, and FinOps

Rightsizing, Savings Plans, Spot, and FinOps are the cost controls that turn AWS billing from a surprise into an engineered feedback loop. The outcome is not simply a lower bill. The outcome is a workload whose capacity, purchase model, interruption tolerance, and ownership model match what the application actually needs.

In this cost and capstone section, these practices connect earlier AWS engineering topics to financial operation. EC2, Auto Scaling, CloudWatch, tagging, IAM, and Cost Explorer all matter because AWS cost is produced by live resources, regional pricing, utilization over time, and commitments that continue after the deployment is forgotten. A good engineer can explain why a resource exists, how hard it works, what pricing model pays for it, and what signal would prove the choice is still correct.

Purpose and Outcome

Rightsizing changes the shape of running resources: instance family, size, storage class, provisioned throughput, or replica count. Savings Plans change the price of steady compute usage in exchange for an hourly spend commitment. Spot uses spare EC2 capacity at a discount but can be interrupted by AWS when capacity is reclaimed. FinOps is the operating model that assigns accountability, budgets, forecasts, review cadence, and decision rights so optimization does not depend on heroic one-time cleanup.

The practical outcome is a cost posture with four layers. First, remove waste such as stopped experiments, unattached volumes, idle NAT gateways, or oversized instances. Second, rightsize resources using utilization evidence and performance requirements. Third, buy discounted commitment only for usage that is durable enough to justify it. Fourth, place interruptible, stateless, or checkpointed work on Spot while keeping enough On-Demand or committed baseline to protect availability.

How the Mechanisms Work

AWS charges most services through metered dimensions: instance-hours, vCPU-hours, GB-months, requests, data transfer, provisioned capacity, or consumed capacity. The bill is assembled from usage records, pricing dimensions, discounts, credits, taxes, and linked-account allocation. Cost Explorer, Cost and Usage Reports, Budgets, Compute Optimizer, and CloudWatch expose different slices of the same economic reality.

Rightsizing starts by comparing provisioned capacity with observed demand. For EC2 this usually means CPU, memory, network, disk throughput, and burst behavior. CPU is available by default in CloudWatch. Memory requires the CloudWatch agent or another telemetry path because the hypervisor cannot see guest memory use directly. For RDS, rightsizing includes CPU, memory pressure, connections, read and write IOPS, storage throughput, and failover requirements. For EBS it may mean changing volume type, size, provisioned IOPS, or throughput rather than changing the instance.

Savings Plans apply automatically to eligible compute usage after purchase. A Compute Savings Plan is flexible across instance family, size, Availability Zone, Region, operating system, and tenancy for EC2, and also covers Fargate and Lambda. EC2 Instance Savings Plans are less flexible but typically offer larger discounts for a chosen instance family in a Region. Both are expressed as a dollars-per-hour commitment for one or three years. The important internal idea is coverage: every hour AWS applies the plan benefit to eligible usage up to the commitment, then charges the rest at normal rates. Unused commitment in an hour is still paid.

Spot capacity is not a discount code; it is a different capacity source. EC2 spare capacity is organized by pools, where a pool is an instance type in an Availability Zone. Interruption risk varies by pool and changes as AWS reclaims capacity. Auto Scaling groups and EC2 Fleet can diversify across pools using allocation strategies such as capacity-optimized or price-capacity-optimized. Applications must handle a two-minute interruption notice, checkpoint work, drain connections, or retry jobs elsewhere.

FinOps supplies the control loop. Inform by giving teams timely, allocated cost data. Optimize by choosing concrete actions such as rightsizing, scheduling, storage lifecycle changes, commitment purchases, or Spot adoption. Operate by measuring results, assigning owners, and preventing regression. Without that loop, cost work becomes a cleanup event rather than a property of the system.

Syntax, Configuration, and API Anatomy

The most common AWS inputs are tags, Cost Explorer filters, CloudWatch metrics, Compute Optimizer recommendations, Auto Scaling mixed instance policies, and purchase settings. Tags such as Application, Environment, Owner, and CostCenter make cost allocation possible, but they only help after activation as cost allocation tags. Cost Explorer queries use a time period, granularity, metric list, optional grouping, and optional filter. CloudWatch metric queries use namespace, metric name, dimensions, statistic, and period.

For commitments, the anatomy is commitment amount, term, payment option, plan type, and scope. The design question is not whether a discount is available; it is how much hourly spend remains stable after expected deploys, migrations, business seasonality, and rightsizing. For Spot, the configuration anatomy is desired capacity, allowed instance types, purchase options, allocation strategy, capacity rebalance, health checks, and termination handling in the workload.

Worked Example 1: Rightsizing Evidence

This example classifies instances from peak percentile CPU and memory. It is deliberately small, but it shows the required habit: do not downsize from average CPU alone. Memory pressure can make an instance unsafe to shrink even when CPU looks idle.

instances = [
    {"id": "i-api-a", "type": "m6i.large", "vcpu": 2, "memory_gib": 8, "cpu_p95": 18, "mem_p95": 42},
    {"id": "i-worker-a", "type": "c6i.xlarge", "vcpu": 4, "memory_gib": 8, "cpu_p95": 71, "mem_p95": 38},
    {"id": "i-cache-a", "type": "r6i.large", "vcpu": 2, "memory_gib": 16, "cpu_p95": 11, "mem_p95": 81},
]

for item in instances:
    if item["cpu_p95"] < 25 and item["mem_p95"] < 60:
        action = "downsize or consolidate"
    elif item["cpu_p95"] > 65 or item["mem_p95"] > 75:
        action = "keep size and inspect bottleneck"
    else:
        action = "watch"
    print(f'{item["id"]}: {action}')

The deterministic output is i-api-a: downsize or consolidate, i-worker-a: keep size and inspect bottleneck, and i-cache-a: keep size and inspect bottleneck. The API node has low CPU and memory, so it is a rightsizing candidate. The worker is CPU-heavy, and the cache is memory-heavy, so a smaller instance may create latency or eviction failures.

Worked Example 2: Savings Plan Coverage

The next example estimates monthly effect from a fixed hourly commitment. It models the important rule: the plan discounts only the portion of eligible hourly spend covered by the commitment. Overcommitting can waste money even when the discount percentage is attractive.

hourly_od = 1.36
covered_rate = 0.88
hours_per_month = 730
steady_instances = 6
commitment = 4.50

monthly_on_demand = hourly_od * steady_instances * hours_per_month
covered_spend = min(commitment, hourly_od * steady_instances) * hours_per_month
uncovered_spend = max(0, hourly_od * steady_instances - commitment) * hours_per_month
monthly_with_plan = covered_spend * (covered_rate / hourly_od) + uncovered_spend
print(f"on_demand=${monthly_on_demand:,.2f}")
print(f"with_plan=${monthly_with_plan:,.2f}")
print(f"estimated_savings=${monthly_on_demand - monthly_with_plan:,.2f}")

The expected output is on_demand=$5,956.80, with_plan=$4,051.50, and estimated_savings=$1,905.30. In a real review, you would repeat this across months, remove workloads scheduled for retirement, and leave headroom for rightsizing before purchasing.

Worked Example 3: Spot Pool Diversification

This example selects Spot pools by a simplified interruption score, then fills desired capacity across more than one instance type. The real AWS allocation strategy uses AWS capacity signals, but the design principle is the same: avoid depending on one scarce pool.

capacity = {
    "m6i.large": {"on_demand": 8, "spot": 16, "interruption_score": 2},
    "m6a.large": {"on_demand": 8, "spot": 20, "interruption_score": 3},
    "m5.large": {"on_demand": 8, "spot": 4, "interruption_score": 6},
}
needed = 24
chosen = []
for instance_type, data in sorted(capacity.items(), key=lambda pair: pair[1]["interruption_score"]):
    use = min(data["spot"], needed)
    if use:
        chosen.append((instance_type, use))
        needed -= use
    if needed == 0:
        break
print(chosen)
print(f"unfilled={needed}")

The output is [('m6i.large', 16), ('m6a.large', 8)] and unfilled=0. The fleet avoids the higher-risk pool because two lower-risk pools satisfy demand. If the workload required exactly one instance type, the discount might be higher for a moment but replacement capacity would be more fragile.

Design Choices and Trade-Offs

Rightsizing trades unused headroom against performance risk. For a stateless service behind Auto Scaling, smaller instances plus more replicas may improve failure isolation and bin packing. For a database, the same move can increase memory pressure, I/O wait, and failover time. The safer pattern is to define minimum performance signals, change one resource dimension at a time, and compare before and after behavior over representative traffic.

Savings Plans trade flexibility for lower rates. A broad Compute Savings Plan is useful when teams use mixed compute services or frequently change instance families. An EC2 Instance Savings Plan can be better for a durable fleet that will remain in a specific family and Region. The engineering mistake is buying commitment before removing waste. Commitments should cover the conservative floor of usage after expected optimization, not the current inflated bill.

Spot trades availability of capacity for price. It fits batch rendering, CI workers, analytics jobs, containerized queue consumers, and other retryable work. It is a poor fit for single-instance databases, stateful systems without fast recovery, or services whose user-facing error budget cannot absorb interruption. Mixed purchase models are often best: On-Demand or committed baseline for minimum service, Spot for elastic surge.

Failure Modes and Troubleshooting

Symptom: cost drops after downsizing, then p95 latency and error rate rise. Cause: the decision used average CPU while ignoring memory, network, garbage collection, or disk wait. Diagnosis: compare pre-change and post-change CloudWatch metrics, application latency, saturation, and deployment timestamps. Check whether alarms fired only after the smaller size was rolled out. Correction: roll back instance size or replica count, add missing memory or I/O telemetry, and rerun the test with p95 or p99 load instead of averages.

Symptom: a Savings Plan was purchased but the bill did not fall as expected. Cause: eligible usage was lower than the hourly commitment, or the workload moved to an ineligible shape or account coverage pattern. Diagnosis: inspect Savings Plans utilization and coverage reports by hour and linked account. Compare unused commitment with On-Demand charges. Correction: stop further purchases, shift eligible steady usage where appropriate, or wait for term expiration while preventing a repeat through purchase review gates.

Symptom: Spot workers terminate in bursts and queue age climbs. Cause: the fleet depended on too few pools or the application did not drain and checkpoint on interruption. Diagnosis: inspect Auto Scaling activity, interruption notices, queue depth, job retry counts, and selected instance types per Availability Zone. Correction: add more compatible instance types, use a capacity-aware allocation strategy, enable capacity rebalance, lower per-job checkpoint interval, and keep an On-Demand floor for urgent work.

Security, Performance, and Reliability Implications

Cost tooling needs read access to billing, Cost Explorer, CloudWatch, Compute Optimizer, tagging, and sometimes Organizations data. Grant review roles read-only access first. Purchase permissions for Savings Plans and Reserved Instances should be tightly restricted because a mistaken purchase creates long-lived financial impact. Automation that stops or resizes resources needs change controls, exclusions for critical systems, and dry-run reporting before action.

Performance risk appears when cost changes remove capacity that was silently absorbing traffic spikes. Reliability risk appears when Spot interruption handling is assumed instead of tested. Cost allocation data can also expose sensitive business information, such as project names, customer-specific environments, or revenue patterns, so dashboards and exports should be shared deliberately.

Hands-On Lab

Prerequisites: an AWS account with Cost Explorer enabled, AWS CLI configured, permission to read Cost Explorer data, and a tagged nonproduction workload or sample account data. Use read-only commands for the lab. Do not purchase a Savings Plan or terminate resources during the exercise.

  1. Choose one application tag, such as Application=training-api, and confirm the tag is activated for cost allocation if you need billing reports by tag.
  2. Run a Cost Explorer query for the last 14 days grouped by service. This identifies whether compute, storage, database, data transfer, or another category deserves attention first.
  3. Open CloudWatch or Compute Optimizer for the top compute resource and record CPU, memory if available, network, and error or latency signals for the same period.
  4. Classify each finding as waste removal, rightsizing, commitment candidate, Spot candidate, or no action. A production database with high memory pressure is usually no action even if CPU is low.
  5. For one safe nonproduction EC2 or Auto Scaling workload, propose a smaller size or wider mixed instance policy. Record the rollback command or previous launch template version before applying any future change.
  6. Verify by comparing cost, latency, errors, saturation, and queue age after at least one representative traffic cycle.
set -euo pipefail

START_DATE="$(date -u -d '14 days ago' +%Y-%m-%d)"
END_DATE="$(date -u +%Y-%m-%d)"

aws ce get-cost-and-usage   --time-period Start="$START_DATE",End="$END_DATE"   --granularity DAILY   --metrics UnblendedCost UsageQuantity   --group-by Type=DIMENSION,Key=SERVICE   --filter '{"Dimensions":{"Key":"RECORD_TYPE","Values":["Usage"]}}'   --output json

Verification: the command should return JSON containing daily ResultsByTime entries and service groups with UnblendedCost amounts. If it returns an access error, the role needs Cost Explorer read permissions. Cleanup: remove any temporary local notes that contain account identifiers, and do not leave experimental automation enabled unless it has an owner, exclusions, and rollback instructions.

Assessment Exercises

  1. A service averages 12 percent CPU but reaches 88 percent memory at p95. What additional evidence would you require before downsizing, and why?
  2. Your organization has $20 per hour of steady EC2 usage today, but a migration will move half of it to Lambda next quarter. What Savings Plan commitment would you consider, and what would you exclude?
  3. A batch fleet on Spot misses its completion target twice a week. Design a mixed capacity strategy that protects deadline-sensitive work without abandoning Spot entirely.
  4. A team disputes its monthly chargeback because shared NAT gateway and data transfer costs are untagged. What allocation rule or account structure would make the next report defensible?
  5. Describe a rollback plan for an Auto Scaling rightsizing change. Include the signal that triggers rollback and the AWS object you would restore.

Summary

Rightsizing, Savings Plans, Spot, and FinOps work together when each decision is tied to evidence. Rightsizing removes mismatches between provisioned and required capacity. Savings Plans discount durable compute usage, but punish overconfident commitments. Spot lowers cost for interruption-tolerant capacity, but requires pool diversity and recovery behavior. FinOps makes the loop repeatable by assigning ownership, measurement, and review cadence. In AWS cloud engineering, cost optimization is strongest when it is treated as part of system design rather than a report after deployment.