Omni FinOps

How to rightsize EC2 and RDS instances without guessing

Use two weeks of CPU to pick instances and databases that can drop a size, what to check before resizing, and how to do it safely.

Mateo VargasUpdated · 4 min read
Contents
  1. Why one size down, and why 40%
  2. Find the candidates on EC2
  3. Check before you resize
  4. Resize an EC2 instance
  5. Rightsize an RDS database
  6. On Google Cloud
  7. Make it stick

In short

  • If peak CPU stayed under 40% for two weeks, half the vCPUs still leaves headroom.
  • CloudWatch doesn’t measure memory without the agent: check it before you resize.
  • Resizing restarts the instance; a Multi-AZ database fails over instead.

Most instances are sized once, at launch, for a load someone expected. If the load never came, you pay for headroom nobody uses, every hour. Rightsizing means moving those instances one size down, with evidence that the smaller size still fits.

The rule this guide follows: if an instance’s CPU never peaked above 40% in two weeks, half the vCPUs still leave headroom above that peak. Move it one size down in the same family, after checking memory.

Why one size down, and why 40%

Within a family, each size down halves the vCPUs and memory. An m5.2xlarge has 8 vCPUs, an m5.xlarge has 4. If the 8-vCPU instance peaked at 40%, the same work on 4 vCPUs would peak around 80%. That’s busy but not saturated.

The on-demand price roughly halves too. As of October 2026, an m5.large is $0.096 an hour in us-east-1 (EC2 pricing); each size up from there costs about twice the one before.

One step at a time keeps the change safe. If two steps look possible, take one, watch it for two weeks, then decide again.

Find the candidates on EC2

Pull the daily peak CPU for two weeks for each running instance:

aws cloudwatch get-metric-statistics \
  --namespace AWS/EC2 --metric-name CPUUtilization \
  --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
  --start-time 2026-09-27T00:00:00Z --end-time 2026-10-11T00:00:00Z \
  --period 86400 --statistics Maximum \
  --query 'max_by(Datapoints, &Maximum).Maximum'

Under 40% makes it a candidate. Under 25% makes it a strong one. If CPU stays under 5% all day, the instance isn’t oversized, it’s idle: see idle EC2 instances.

AWS Compute Optimizer gives a second opinion at no additional charge, with enhanced metrics available for about $0.25 per resource a month as of October 2026 (pricing):

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

Check before you resize

CPU is half the picture. Check these before every change:

  • Memory. CloudWatch doesn’t measure memory on EC2 unless the CloudWatch agent is installed. Without it, you’re guessing. Install the agent, or look at the application’s own memory metrics, before you halve the RAM.
  • Network and EBS throughput. Smaller sizes often have lower network and EBS bandwidth limits. A file server or a database replica can hit those before CPU.
  • Burstable types. Moving to a t family saves more but runs on CPU credits. A workload that bursts for long stretches will run out.
  • Auto Scaling groups. Don’t resize a group member by hand. The group replaces it with the old size on the next scale event.

Resize an EC2 instance

A standalone instance has to stop to change type. Plan a short window:

aws ec2 stop-instances --instance-ids i-0123456789abcdef0
aws ec2 wait instance-stopped --instance-ids i-0123456789abcdef0
aws ec2 modify-instance-attribute --instance-id i-0123456789abcdef0 \
  --instance-type "{\"Value\": \"m5.xlarge\"}"
aws ec2 start-instances --instance-ids i-0123456789abcdef0

To roll back, run the same commands with the old type.

For an Auto Scaling group, change the launch template and let an instance refresh replace the instances gradually:

aws ec2 create-launch-template-version --launch-template-id lt-0123456789abcdef0 \
  --source-version '$Latest' --launch-template-data '{"InstanceType":"m5.xlarge"}'
aws autoscaling update-auto-scaling-group --auto-scaling-group-name web-asg \
  --launch-template 'LaunchTemplateId=lt-0123456789abcdef0,Version=$Latest'
aws autoscaling start-instance-refresh --auto-scaling-group-name web-asg \
  --preferences '{"MinHealthyPercentage":90}'

Rightsize an RDS database

RDS follows the same rule on CPUUtilization in the AWS/RDS namespace, with the DBInstanceIdentifier dimension. Memory is easier here: RDS reports FreeableMemory without any agent. If freeable memory stays high, the smaller class is likely fine.

aws rds modify-db-instance --db-instance-identifier db-reporting \
  --db-instance-class db.r5.xlarge --apply-immediately

Without --apply-immediately, the change waits for the next maintenance window. How disruptive it is depends on the deployment:

Deployment What happens during the change
Single-AZ The database restarts, typically for a few minutes
Multi-AZ It fails over to the standby, with a brief blip

Schedule single-AZ changes for a quiet hour, and make sure the application reconnects on its own.

On Google Cloud

Compute Engine VMs follow the same rule. Google’s machine type recommender gives a second opinion:

gcloud recommender recommendations list \
  --project=my-project --location=us-central1-a \
  --recommender=google.compute.instance.MachineTypeRecommender

Memory needs the Ops Agent, the same way EC2 needs the CloudWatch agent. Changing the machine type also needs the VM stopped:

gcloud compute instances stop etl-worker-2 --zone=us-central1-a
gcloud compute instances set-machine-type etl-worker-2 \
  --zone=us-central1-a --machine-type=n2-standard-4
gcloud compute instances start etl-worker-2 --zone=us-central1-a

Make it stick

Rightsizing decays. New instances get launched at the old size, and load changes. Check again every few weeks, and change the launch templates and infrastructure code too, or the next deploy undoes the work.

The opposite also happens: an instance averaging above 80% CPU is the one to move up a size before it throttles. Omni FinOps flags both directions on every refresh, with the command for each.

Rightsize before you commit. A Compute Savings Plan sized on oversized instances locks in spend you were about to remove. And if the software runs on arm64, the step down can be a step across too: see moving to Graviton.

Mateo Vargas writes Omni FinOps’ cost guides, from the same rules the product runs on every refresh. Prices are list prices in us-east-1 or us-central1 as of October 11, 2026; check your region’s pricing page.

More guides