Skip to content

Compute Optimizer right-sizing — where it sees clearly, where it is blind, and the gating rules

Compute Optimizer reads 14 days of CloudWatch and recommends right-sizes across EC2, ASG, Lambda, and EBS. The engine is genuinely good but it is blind to spiky workloads and burstable credit. Here is how to accept the recommendations safely.

The Compute Optimizer dashboard for an established AWS account in 2026 shows 47 EC2 right-sizing recommendations with $11k/month in projected savings. The recommendations look defensible — most are downsizes by one step (m6i.2xlarge to m6i.xlarge, r6i.4xlarge to r6i.2xlarge). The temptation is to bulk-accept and capture the savings. The right move is to read each recommendation against the workload shape, because Compute Optimizer is genuinely good at steady-state workloads and blind to two specific patterns that show up in the recommendations anyway. This article pairs with the p95 right-sizing approach — Compute Optimizer is the engine, p95 is the gate.

What’s happening

Compute Optimizer is AWS’s right-sizing engine. It reads 14 days of CloudWatch metrics (CPU, memory if the CloudWatch agent is installed, network I/O, EBS IOPS, EBS throughput), runs them against a library of instance type benchmarks, and recommends a target type. The recommendation includes a performance risk score (low/medium/high), projected savings, and the metrics that drove the decision.

The covered resource types:

  • EC2 instances — instance-type recommendations against the workload’s actual usage.
  • Auto Scaling groups — group-level recommendations including instance type and the suggested mix.
  • Lambda functions — memory size recommendations (because Lambda’s CPU is allocated proportionally to memory, this is also an indirect CPU recommendation).
  • EBS volumes — type recommendations (gp2 → gp3 is the classic), and IOPS/throughput right-sizing for gp3 and io2.
  • ECS services on Fargate — task-level CPU/memory recommendations.
  • RDS instances (since 2024) — engine, version, instance class.

The 14-day window is the key calibration. Compute Optimizer assumes the trailing 14 days are representative. For most steady-state workloads this is fine. For workloads where the 14-day window misses a known peak — end-of-month batch, the quarter-end report, the annual compliance run — the recommendations are calibrated against a quieter period and the recommendation will be too aggressive.

The places where the engine is blind:

  • Spiky workloads. A workload that runs at 5% CPU for 23 hours and 95% CPU for 1 hour has an average around 8%, which looks like a clear over-spec. Compute Optimizer’s averaging will recommend a downsize that cannot absorb the hourly spike. The performance risk score is supposed to flag this, but it only catches the most extreme spikes; the moderate ones slip through with a Low risk score.
  • Burstable instance families (t3, t4g). The CPU utilization metric on a burstable instance reads low because the instance is throttling when credits are exhausted — the workload would consume more CPU if more were available, but the throttling looks like underutilization. Compute Optimizer respects this for the most part but the recommendations sometimes propose downsizing within the burstable family to a smaller t-class, which compounds the credit-exhaustion problem.
  • Memory-bound workloads without the CloudWatch agent. Without the agent installed, Compute Optimizer has no memory data and treats the recommendation as memory-blind. The recommendation might downsize a memory-bound r6i.xlarge to a CPU-equivalent c6i.xlarge that has half the memory, and the workload OOMs.
  • Workloads with network or EBS throughput constraints not captured by averages. A workload that is bursty on network I/O and never CPU-bound looks idle to the engine. The right-size to a smaller instance type might cross the network throughput cap on the smaller instance during a burst that the larger instance absorbed transparently.

How to verify

Pull the current set of recommendations:

aws compute-optimizer get-ec2-instance-recommendations \
  --query 'instanceRecommendations[].[instanceArn,currentInstanceType,recommendationOptions[0].instanceType,recommendationOptions[0].performanceRisk,recommendationOptions[0].projectedUtilizationMetrics[?name==`CPU`].value|[0]]' \
  --output table

For each recommendation, get the detail on the metrics that drove it:

aws compute-optimizer get-ec2-instance-recommendations \
  --instance-arns arn:aws:ec2:us-east-1:123:instance/i-0123456789abcdef0 \
  --query 'instanceRecommendations[].utilizationMetrics' \
  --output yaml

The utilizationMetrics block lists the maximum, average, and percentile values the engine saw over the 14-day window. The values to spot:

  • If CPU.value shows a maximum near 100% but an average near 5%, the workload is spiky and the recommendation is unsafe without a manual check.
  • If memory metrics are absent (no MEMORY row in the output), the recommendation is memory-blind.
  • If the network metrics show a maximum near the instance’s bandwidth cap, the workload is network-bound and the downsize may cross the smaller instance’s cap.

For the workload-specific gating, run the p95 CloudWatch query from the right-sizing-by-p95 article on the same instance. Compute Optimizer’s recommendation and the per-minute p95 should agree. If Compute Optimizer says downsize and the per-minute p95 is above 70%, the engine is averaging through a spike.

The fix

The gating rules before accepting any Compute Optimizer recommendation:

  1. Check the performance risk score. Accept Low risk recommendations on steady-state workloads. Hold Medium and High risk recommendations for a manual review. The risk score reflects the engine’s confidence; if it is hedging, take the hedge seriously.

  2. Run the per-minute p95 query in parallel. For every Low-risk downsize candidate, pull the per-minute p95 CPU over the same 14-day window:

    aws cloudwatch get-metric-statistics \
      --namespace AWS/EC2 \
      --metric-name CPUUtilization \
      --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
      --start-time $(date -u -v-14d +%Y-%m-%dT%H:%M:%S) \
      --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
      --period 60 \
      --extended-statistics p95 \
      --query 'Datapoints[].ExtendedStatistics.p95' \
      --output text | sort -n | tail -1

    The maximum per-minute p95 should be below 60% for a one-step downsize to be safe. If Compute Optimizer says downsize but per-minute p95 is 78%, the engine averaged through a spike.

  3. Check the workload shape (burstable family). If the instance is t3/t4g, pull CPUCreditBalance:

    aws cloudwatch get-metric-statistics \
      --namespace AWS/EC2 \
      --metric-name CPUCreditBalance \
      --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
      --start-time $(date -u -v-14d +%Y-%m-%dT%H:%M:%S) \
      --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
      --period 300 \
      --statistics Minimum \
      --query 'Datapoints[].Minimum' \
      --output text | sort -n | head -1

    The minimum credit balance over 14 days. If it ever hits zero, the instance was CPU-throttled and the CPU metric is artificially low. Do not downsize within the burstable family. Switch the workload off burstable entirely (to c6i or m6i) or move up within burstable to a larger t-class.

  4. Confirm memory data is present. If Compute Optimizer says downsize and MEMORY is absent from utilizationMetrics, the recommendation is memory-blind. Install the CloudWatch agent, wait two weeks for the metric history to populate, then re-evaluate.

  5. Check the daily peak alignment. Pull the metric grouped by hour-of-day to see when the spike happens:

    aws cloudwatch get-metric-statistics \
      --namespace AWS/EC2 \
      --metric-name CPUUtilization \
      --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
      --start-time $(date -u -v-14d +%Y-%m-%dT%H:%M:%S) \
      --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
      --period 3600 \
      --extended-statistics p95 \
      --query 'Datapoints[?ExtendedStatistics.p95 > `60`]' \
      --output yaml

    The output rows are the hours that exceeded 60% p95. If they cluster at a specific time (03:00 UTC for a nightly batch, 13:00 UTC for a business-hours peak), the smaller instance type will hit that peak harder. The downsize may still be safe, but the on-call should be informed of the hour-of-day so the next incident is not a surprise.

  6. Right-size one step at a time. Compute Optimizer sometimes recommends a two-step downsize (m6i.4xlarge to m6i.xlarge). Accept the one-step recommendation first (m6i.4xlarge to m6i.2xlarge), watch for a business cycle, then accept the next step if the new instance still sits comfortably. The savings are 90% captured at the first step; the marginal gain on the second step is rarely worth the doubled risk.

  7. Wait one business cycle after each resize. Confirm at the new size that the workload’s per-minute p95 lands in the 40-60% comfort band before accepting the next recommendation for the same instance.

For ASG recommendations, the gating is slightly different. Compute Optimizer evaluates the instance type but the ASG mix and scaling policy interact in ways the engine does not model. An ASG running a target-tracking policy at 50% CPU on m6i.xlarge is the right configuration; a downsize to m6i.large would just cause the ASG to launch twice as many instances, with no net cost change and worse instance-level reliability. Accept ASG recommendations only when the target-tracking policy is reviewed at the same time.

For Lambda recommendations, the engine’s memory-tuning suggestion is usually right because Lambda’s billing model is straightforward (GB-seconds), and a function that runs in 800 MB at 200 ms might run in 1 GB at 120 ms and cost less overall. Accept these freely; the rollback is one parameter change.

For EBS recommendations, the gp2-to-gp3 migration is essentially free money — gp3 is faster and cheaper than gp2 for the vast majority of workloads. Accept these in bulk. The IOPS/throughput right-sizing on gp3/io2 deserves more care because a downsize past the workload’s burst envelope causes throughput throttling that looks like application latency.

Three rules across every Compute Optimizer engagement:

Risk score Low + p95 < 60% = accept. The two signals agreeing is the safe-to-accept band. Either one alone is not enough.

Burstable family workloads need credit-balance check. Compute Optimizer respects burstable mostly, but the recommendations on t-class workloads need the credit-balance check before any downsize.

One step, one business cycle, then re-evaluate. Stacking right-sizes without waiting for the metric history compounds the risk on every step.

The Compute Optimizer pass on a 200-instance fleet, with the gating discipline applied, captures 60-80% of the engine’s projected savings safely. The 20-40% the team rejects on gating grounds are the recommendations that would have caused incidents — and the engine’s risk score did not always flag them, which is why the manual gate exists.


Stack Harbor runs IAM cleanup, CloudWatch baseline, AWS Backup, and the cost-control rhythm as part of Managed AWS and ongoing Managed Cloud Ops. If Compute Optimizer’s recommendations sit in the dashboard for months because nobody has time to validate them, start with an infrastructure consult.