Skip to content

EC2 rightsizing in practice: beyond what Compute Optimizer tells you

AWS EC2 rightsizing beyond Compute Optimizer: get memory metrics in place, account for burst credits and app constraints, and downsize without causing an incident.

Compute Optimizer is a fine starting point for EC2 rightsizing, but it only sees what CloudWatch sees — and by default CloudWatch does not see memory. In practice, real rightsizing is a three-step exercise: get memory telemetry installed so recommendations stop being CPU-only guesses, overlay what the tool cannot know (burst credits, license terms, JVM heaps, failover headroom), and then downsize one instance at a time with a fast path back. The tool proposes; the operator disposes.

What’s happening

Compute Optimizer analyzes CloudWatch utilization history — 14 days by default, up to 93 days if you pay for enhanced infrastructure metrics — and recommends instance types with better fit. We covered the tool itself in Compute Optimizer rightsizing; this article is about the gap between its recommendation and a safe change.

The gaps that matter in production. First, memory is invisible without the CloudWatch agent: an instance at 20% CPU and 92% RAM looks like a downsizing candidate to any CPU-only analysis, and shrinking it produces an OOM-killing incident, not a saving. Second, burstable instances lie at a glance: a t3.large at 15% average CPU may be living off CPU credits, and the “obvious” move to a smaller t3 collapses when credits run out. Third, the tool does not know your application: a JVM with a fixed 12 GB heap, a vendor license priced per core, a node deliberately sized to absorb a partner node’s failover — all look like waste in a utilization graph. Fourth, lookback windows miss slow cycles: month-end closes, seasonal peaks, an annual audit batch. A 14-day window in mid-July knows nothing about January.

What to check first

  • Is the CloudWatch agent deployed? If there is no CWAgent namespace in CloudWatch metrics, every recommendation you have is CPU/network-only. Fix this before acting on anything.
  • Which instances are burstable? Anything in the T family needs its credit balance examined, not just its CPU average.
  • What generation are you on? An m4 or m5 at healthy utilization still costs more than the equivalent current-generation instance; same-size generation upgrades are the lowest-risk saving available.
  • Are the candidates in an Auto Scaling group? Then rightsizing means editing the launch template and letting rotation do the work — a different, safer procedure than resizing pets.
  • What is the peak, not the average? Pull p95/max over 90 days, not the 2-week mean.

How to verify

# Compute Optimizer's current view
aws compute-optimizer get-ec2-instance-recommendations \
  --query 'instanceRecommendations[].[instanceArn,finding,currentInstanceType,recommendationOptions[0].instanceType]' \
  --output table

# Peak CPU over 90 days, daily maximums — not the average
aws cloudwatch get-metric-statistics --namespace AWS/EC2 \
  --metric-name CPUUtilization \
  --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
  --start-time 2026-04-05T00:00:00Z --end-time 2026-07-04T00:00:00Z \
  --period 86400 --statistics Maximum

# Memory, if the CloudWatch agent is reporting
aws cloudwatch get-metric-statistics --namespace CWAgent \
  --metric-name mem_used_percent \
  --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
  --start-time 2026-06-04T00:00:00Z --end-time 2026-07-04T00:00:00Z \
  --period 3600 --statistics Maximum

# Burst credit balance for T-family instances
aws cloudwatch get-metric-statistics --namespace AWS/EC2 \
  --metric-name CPUCreditBalance \
  --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
  --start-time 2026-06-27T00:00:00Z --end-time 2026-07-04T00:00:00Z \
  --period 3600 --statistics Minimum

Console paths: EC2 > Instances > Monitoring for per-instance graphs, Compute Optimizer > EC2 instances for the findings list. A credit balance that trends toward zero during business hours disqualifies a T-family downsize. The instance-type change mechanics are in the EC2 documentation.

The runbook

  1. Deploy the CloudWatch agent fleet-wide first. Via SSM Distributor or your config management, with mem_used_percent at minimum. Then wait two weeks — acting on CPU-only data is how rightsizing gets its bad reputation.
  2. Take the free wins: generation upgrades. Same size, newer family (m5.xlarge to m7g.xlarge where ARM is viable, or m7i.xlarge where it is not) cuts cost at equal or better performance with no capacity risk. Check Graviton compatibility separately — that is a port decision, not a resize.
  3. Downsize the clear cases one step at a time. Candidates with p95 CPU under ~30% and p95 memory under ~50% over 90 days drop one size, never two. Stop, change instance type, start — this is minutes of downtime for a standalone instance, so schedule it; for ASG-managed fleets, update the launch template and roll.
  4. Watch each change for a full business cycle. CPU, memory, and the application’s own latency metrics for at least a week — including whatever weekly batch the instance secretly runs.
  5. Handle burstables explicitly. If a T instance burns credits daily, it is undersized regardless of its average; move it up or to a fixed-performance family. If it never touches credits, it may be a candidate for one size down.
  6. Document the exceptions. Instances kept large for heap, license, or failover reasons get a tag saying so — otherwise next quarter’s hunt re-litigates the same instances.

When this is the wrong move

Do not rightsize during or right before your peak season; the savings are permanent but so are the incident reports. Skip instances slated for containerization or replacement within the quarter — the effort is better spent on the migration. And in an Auto Scaling group whose policies already track utilization, aggressive per-instance shrinking mostly just increases instance count; tune the group’s scaling target instead.

Common mistakes

  • Trusting a downsize recommendation computed without memory metrics.
  • Resizing two sizes down in one jump because the graphs looked flat — the failure mode is nonlinear.
  • Ignoring EBS bandwidth and network baseline: smaller instances get smaller EBS throughput and network allowances, which can bottleneck an I/O-heavy workload whose CPU was idle.
  • Rightsizing the instance but not the commitment plan — shrink first, then size your Savings Plan floor, in that order.

Prevention

  • Keep the CloudWatch agent in every AMI or launch template so memory data always exists.
  • Run a quarterly rightsizing review with a 90-day lookback; small regular passes beat annual purges.
  • Enforce current-generation instance types in new launch templates.
  • Record sizing rationale in tags (sizing:reason=jvm-heap-12g) to make future reviews fast.
  • Track the fleet-wide p95 utilization as a KPI so drift is visible before the bill says so.

Rightsizing is not a tool output; it is a habit with telemetry behind it. If nobody on your team truly owns the AWS environment end to end, that is the root of most of these problems — Stack Harbor runs AWS accounts daily under AWS Operations, and you can book an AWS review.