How do you rightsize AWS instances without breaking production? Measure real utilization over a representative window, set a headroom target, then change one workload at a time behind a tested rollback while you watch latency and errors — not just CPU. Rightsizing is matching resource size to how a workload actually behaves, and it goes wrong the moment someone resizes from a Compute Optimizer number instead of from the workload’s traffic. Do it data-first and it is one of the safest cost levers you have; do it from a spreadsheet and it is how a cost review becomes an incident.
This is the deep version of the “right-size” week that the 30-day cloud cost cleanup schedules but deliberately does not fully document — that guide gives you the calendar, this one gives you the safe method. It also belongs in a specific place in the sequence: rightsize after you have measured and before you commit to Savings Plans or Reserved Instances, because a one- or three-year commitment locks in whatever waste you failed to remove first.
What is rightsizing, and why does it break production?
Rightsizing is matching a resource’s size to its actual utilization without degrading performance — right CPU, right memory, right storage class for the load the thing really carries. It breaks production for one reason: people treat the recommendation as the answer. A tool reports 8% average CPU across a fleet, someone drops every instance two sizes, and the p95 that was hiding behind that 8% average now saturates. Latency climbs, the autoscaler thrashes, and the “cost win” turns into a postmortem.
The data-driven version replaces the average with the distribution, the whole fleet with one careful change, and the hope with a rollback. You are not cutting to a number. You are cutting to a headroom bar you decided in advance — and you can only do that honestly if you can attribute each resource to a real workload. Rightsizing the wrong service’s instance just moves the outage around.
How do you measure before you cut?
Measure over a window long enough to contain the workload’s real peaks — a full business cycle, not a quiet weekend. Two sources feed the decision, and both have a trap.
CloudWatch is ground truth for CPU, network, and disk, but it does not see guest memory by default. Memory utilization requires the CloudWatch agent installed on the instance; without it you are rightsizing memory blind, and Compute Optimizer will fall back to defaults or report memory as unavailable. If memory is your binding constraint — and for most application and database workloads it is — install the agent first and let it collect before you trust any recommendation.
AWS Compute Optimizer reads those metrics and produces EC2, Auto Scaling group, EBS, Lambda, and RDS recommendations for free. Its default lookback is roughly 14 days; the longer three-month “enhanced infrastructure metrics” lookback is a paid opt-in (verify current pricing). Fourteen days is fine for a steady service and dangerous for anything with a monthly close, a payroll run, or a seasonal peak that lives outside the window.
The trap that catches everyone: T-family burstable instances (t3, t4g) are supposed to run at low average CPU. That is the design, not waste. A tool that sees 5% average CPU on a t3.large and suggests shrinking it can be flatly wrong — what matters is the CPU credit balance and whether the instance is quietly running in unlimited mode and billing for sustained bursts. Read the credits before you touch a burstable.
Is AWS Compute Optimizer good enough to trust?
Compute Optimizer is a good starting point and a bad autopilot. It is free, native, pulls the right metrics, and its recommendations are a reasonable first draft — genuinely useful for surfacing over-provisioned instances you would never audit by hand. What it does not know is your workload’s tolerance: it does not know that this service has a strict p99 latency SLO, that that one is a batch job where a slower run is fine, or that the 14-day window missed month-end. Treat its output as a ranked list of candidates to investigate, never as a change set to apply. The tool finds the suspects; you decide the verdict.
How much headroom should you leave?
Set the headroom policy before you look at a single recommendation, so the tool proposes and your policy disposes. A defensible default for most regulated-SMB workloads: target steady-state p95 CPU and p95 memory under about 70% after the change, with the instance able to absorb its normal peak without leaning on autoscaling. Use p95, not the average — the average is what lies to you. Latency-sensitive services get more headroom (cut conservatively, one size at a time); batch, dev, and staging get less (cut aggressively, they can tolerate it). Writing the bar down turns rightsizing from an argument into an arithmetic check.
How do you rightsize without downtime?
Change one workload at a time, behind infrastructure you can roll back, and watch the symptoms that actually matter. The safe method is the same shape every time.
| Step | Do this | The guardrail |
|---|---|---|
| 1. Measure | CloudWatch (plus the agent for memory) over a full business cycle; pull Compute Optimizer | No agent means no memory data — don’t rightsize memory blind |
| 2. Set headroom | Target p95 CPU and memory under ~70% post-change; more for latency-SLO services | Decide the bar before you read any recommendation |
| 3. Change one thing | New size via launch template / ASG, one workload at a time | Never batch-resize a fleet from a single average |
| 4. Keep a rollback | Previous launch template version or snapshot ready to reapply | No rollback means don’t touch stateful or prod |
| 5. Watch the right signals | p95/p99 latency and error rate, before and after, for a full cycle | CPU alone will call a latency regression a success |
Two rules keep this from becoming an incident: never rightsize a stateful or production system without a tested rollback and a watch window, and watch latency and error rate, not just CPU. A smaller instance that holds CPU under 70% but doubles p99 latency is a failed change, and the CPU dashboard will happily tell you it succeeded. Make the change in your launch template or Auto Scaling group and land it in your IaC — a resize done by hand in the console is exactly the “someone rightsized by hand” signal that infrastructure drift detection routes to its weekly digest, and if you never backport it, the next terraform apply reverts your saving.
What are the storage and database wins?
Storage is the safest money in the whole exercise, because most of it carries no performance risk at all. Rank it easy-to-hard:
- gp2 → gp3 EBS. gp3 is faster and roughly 20% cheaper at the same provisioned size, and it lets you set IOPS and throughput independently of capacity (verify current pricing for your region). The migration is an online volume modification in most cases. For most volumes it is a strictly better default with no downside, and there is no good reason to keep launching gp2.
- Delete unattached EBS. Volumes sitting in the
availablestate are 100% waste. Snapshot anything recent, then delete the volume. - Snapshot and AMI hygiene. Retire orphaned snapshots and unreferenced AMIs on a retention policy instead of hoarding them forever. “Keep the last 30 days plus month-end for a year” is a sane default.
- S3 lifecycle and Intelligent-Tiering. Move cold objects to cheaper classes on a lifecycle rule, or let Intelligent-Tiering shift them automatically for unpredictable access patterns (it adds a small per-object monitoring charge — worth it above a size threshold, not below).
- RDS rightsizing. The highest-risk item, so it goes last. Compute Optimizer covers RDS, and the gp2 → gp3 move applies here too, but an instance-class change is a maintenance-window event with a real failover. Treat production RDS like production compute: rollback and watch window, never a Friday-afternoon click.
What’s the good-enough bar?
The good-enough bar: every production instance sits under your headroom target at p95 with a tested rollback path, every EBS volume is gp3, nothing unattached is still billing, and every change landed in IaC rather than the console. You do not need per-workload perfection or a commercial rightsizing platform to clear that bar — CloudWatch, Compute Optimizer, and discipline get a 10-to-80-engineer shop there.
The sequencing is the part people skip. Rightsize first, then buy commitments. Buying a three-year Savings Plan over an un-rightsized fleet is committing to your own waste at a discount, which is worse than paying on-demand for waste you can still delete tomorrow. Measure, cut to the bar, then commit with Savings Plans or Reserved Instances against the smaller, true baseline. Never commit to waste.
The Template
Run through it in order. Each box has a clear “done” state; do not start the compute cuts before the measurement boxes are checked.
Before you touch anything
- CloudWatch agent installed wherever memory is the binding constraint
- Metrics collected over a full business cycle (month-end / peak included)
- Compute Optimizer enabled; recommendations pulled for EC2, ASG, EBS, RDS, Lambda
- Every candidate resource attributed to a named workload and owner
- Headroom policy written down (p95 CPU/mem under ~70%; more for latency-SLO services)
- T-family burstables checked for CPU-credit balance, not just average CPU
Making the change (one workload at a time)
- Change lives in the launch template / ASG / IaC, not a console click
- Previous version or snapshot confirmed as a working rollback
- Applied to one workload, in a low-traffic window for anything stateful
- p95/p99 latency and error rate watched before and after, for a full cycle
- Result backported to IaC so drift detection stays quiet
Storage and database sweep
- All gp2 volumes migrated to gp3
- Unattached EBS volumes snapshotted and deleted
- Orphaned snapshots and unreferenced AMIs retired on a retention policy
- S3 lifecycle or Intelligent-Tiering applied to cold data
- RDS rightsized last, treated as a production change (window + rollback)
Only then
- Steady-state baseline re-measured after the cuts
- Savings Plans / RIs sized against the new, smaller baseline — never the old one
Operating Notes
Rightsizing is not a one-time event. Workloads grow back into their instances, someone launches a fresh gp2 volume, a new service ships over-provisioned “to be safe.” Re-run the measurement pass on the same cadence as the 30-day cost cleanup — a couple of times a year — and the estate stays close to its true workload cost instead of drifting back up.
Keep the discipline even when the numbers are small. The habit that saves you is not the single dramatic cut; it is that every change goes through measurement, a rollback, and a watch window, so the day you rightsize something load-bearing, the muscle is already there. The teams that break production rightsizing are the ones who did it carefully ten times, got comfortable, and skipped the rollback on the eleventh.