How to Right-Size EC2 Instances Before You Migrate to Graviton
Graviton is not a shortcut
AWS Graviton instances are cheaper and more power-efficient than many comparable x86 instances. The savings are real, and the carbon footprint is lower. But moving an over-provisioned m5.4xlarge to a Graviton m7g.4xlarge does almost nothing for your bill. You have copied the bloat from one architecture to another.
The actual win comes in two steps: right-size the workload first, then move the smaller shape to Graviton. Teams that skip the first step usually find that their Graviton migration saves less than they expected and sometimes makes performance worse.
This post is about the right-sizing step. It works whether or not you ever migrate to Graviton, but it is the right order if you are planning a migration.
What right-sizing means
Right-sizing means matching the EC2 instance to the actual resource needs of the workload over a realistic time window. It is not the same as downsizing everything by one step. A workload that genuinely needs 16 vCPUs should keep 16 vCPUs. A workload averaging 5% CPU with occasional 30% spikes can usually be much smaller.
The dimensions to check are:
- CPU utilization — average and peak over a business day, week, and month
- Memory utilization — the most common reason a CPU-only downsizing fails
- Network traffic — some smaller instance families have lower network throughput limits
- Disk I/O — if the workload is IOPS-bound, a smaller instance can hurt latency
- GPU or specialized instructions — Graviton does not support all instruction sets
A right-sized instance is one where peak usage reaches 40–70% of capacity without causing latency or queueing. That leaves headroom for traffic spikes and avoids paying for idle cores.
Step 1: collect a baseline
CloudWatch is the cheapest place to start. Pick a window that includes a normal business cycle, not a one-hour quiet period.
Get average and max CPU for the last 14 days:
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
--statistics Average Maximum \
--start-time $(date -v-14d -u +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 3600
For memory, the OS does not push memory utilization to CloudWatch by default. You need the CloudWatch agent installed, or you can use a quick in-guest check with free or vmstat. Without memory data, do not downsize purely on CPU.
A safer pattern for multiple instances is to use AWS Compute Optimizer. It is free and will recommend instance types based on CloudWatch history, including memory if the agent is present. Compute Optimizer will flag over-provisioned and under-provisioned resources in one view.
aws compute-optimizer get-ec2-instance-recommendations
The catch: Compute Optimizer gives you a list, not a dollar impact. It also does not understand your application’s operational constraints, so a recommendation still needs a human review.
Step 2: match the shape to the workload
Once you have the baseline, pick the instance family that fits the resource mix:
| Workload pattern | Good families | What to avoid |
|---|---|---|
| General, balanced CPU and memory | m7g, m7i, m6i, m6g | c7g if you do not need the extra CPU |
| CPU-heavy, low memory | c7g, c7i, c6i | m-family if you are not using the RAM |
| Memory-bound | r7g, r7i, r6i, x2gd | m-family or c-family where RAM becomes the bottleneck |
| Burstable, inconsistent load | t4g, t3, t3a | constant high-load on T-family gets expensive |
| Network or I/O heavy | c7gn, m7i-flex | smaller T or older families |
The cost difference between a current-generation x86 and the same-size Graviton is typically 15–25%. The difference between an over-provisioned m5 and a right-sized Graviton can be 40–60%.
Step 3: check the four common mistakes
1. Downsizing the CPU but not the memory
A c5.2xlarge has 8 vCPU and 16 GiB. A c6g.large has 2 vCPU and 4 GiB. If the application only uses 10% CPU but 12 GiB of RAM, moving to a smaller Graviton CPU will run out of memory quickly. Memory is usually the binding constraint.
2. Ignoring the instance’s network ceiling
Smaller instance families have lower baseline network bandwidth. A service that pushes a lot of data to S3, another service, or the internet can become network-throttled on a smaller type even if CPU and memory look fine.
3. Moving workloads with x86-specific dependencies
Some workloads depend on AVX-512, specific SQL Server builds, third-party binaries, or legacy .NET Framework versions that do not run on Graviton. Graviton is ARM64. Check the dependency list before scheduling a migration. Compute Optimizer will not catch a missing binary.
4. Not testing the new size before cutting over
A right-size should be tested for at least a full business day. Watch error rates, latency, queue depth, and memory pressure. AWS makes it easy to switch instance sizes with a stop and start, so a rollback is fast. Still, test it.
Step 4: run the numbers
Compare the on-demand price of the current instance and the right-sized Graviton alternative. Include:
- On-demand hourly rate difference
- Whether the instance is covered by Savings Plans or Reserved Instances, which may change the effective rate
- Whether the workload is a good fit for Spot, which is often 60–70% cheaper for fault-tolerant workloads
For a single instance running 24/7, an hourly difference of $0.05 becomes $36/month. Across 20 instances it becomes $720/month. Across 200 it becomes $7,200/month. The same math applies to carbon, but the bill is the easier number to defend internally.
Step 5: plan the Graviton cutover
The cleanest sequence is:
- Right-size on x86 first. Get to a stable, smaller shape.
- Validate performance for a week.
- Take an AMI of the right-sized instance.
- Launch a Graviton instance from that AMI or a freshly built image.
- Run a canary on the Graviton instance for a day.
- Switch traffic and decommission the old instance.
Skipping step 1 is the most common reason a Graviton migration underwhelms. The second most common reason is not rebuilding the application for ARM64 and discovering a missing dependency after launch.
How GreenOps Scan can help
The ec2 module in the free GreenOps Scan CLI flags:
- Instances that have been running below 10% CPU for weeks
- Instances that look oversized for their memory footprint
- Older x86 instance families that have cheaper, current-generation alternatives
- Instances running 24/7 without Reserved or Savings Plan coverage
Run it against a dev or sandbox account:
npx greenops-scan --profile dev --region us-east-1 --modules ec2
Or with Docker:
docker run --rm -it \
-v ~/.aws:/home/greenops/.aws:ro \
-v "$(pwd)/reports:/reports" \
-e AWS_PROFILE=dev \
spidgorny/greenops-scan:latest \
--region us-east-1 --modules ec2
Each finding shows the current instance type, the recommended direction, and an estimated monthly saving. Review the recommendation before changing anything; a scan is a starting point, not a replacement for a CloudWatch baseline.
A quick right-sizing checklist
- Collect CPU, memory, and network metrics for at least 7–14 days
- Check Compute Optimizer for broad recommendations
- Map the workload to the right instance family, not just a smaller version of the same family
- Confirm the workload has no x86-only dependencies
- Test the new instance size before production
- Compare on-demand, Spot, and Graviton prices
- Plan the cutover as a canary, not a mass migration
Right-sizing is the most reliable way to cut EC2 cost. Graviton makes the savings bigger. Do the first step before the second.
Tags: #AWS #CloudCostOptimization #FinOps #EC2 #Graviton #RightSizing #CloudWaste #GreenOps
