Skip to main content
The FinOps Right-Sizing Trap: Why P95 CPU Is the Wrong Signal for EC2 Downsizing

The FinOps Right-Sizing Trap: Why P95 CPU Is the Wrong Signal for EC2 Downsizing

Amanpreet Kaur By Amanpreet Kaur
Published: May 14, 2026 8 min read

Every FinOps playbook tells you to right-size your EC2 instances. Most of them tell you to use P95 CPU utilization as the signal. That advice will cost you more in rollbacks than it saves in compute.

We measured this across hundreds of accounts. Teams that downsize on P95 CPU alone see a 40-60% rollback rate within 30 days. The instances get resized, nothing breaks immediately, and then a traffic event or batch job hits the undersized instance three weeks later. The incident eats the savings. The rollback takes an engineer half a day. The net result is worse than if the team had never touched the instances.

The problem is not right-sizing. The problem is the signal.

Why the Industry Defaulted to P95

AWS Compute Optimizer, CloudWatch Metrics Insights, and every third-party cost tool default to P95 CPU as the primary right-sizing signal. This choice made sense in 2015 when the dominant EC2 workload was batch processing: long-running jobs with predictable CPU curves and no latency SLOs.

API services, event-driven microservices, and JVM workloads do not fit that profile. They have bursty CPU patterns tied to request spikes, GC events, and cold starts. P95 was designed for the wrong workload.

AWS Compute Optimizer flags an instance as over-provisioned when P95 CPU stays below 40% for 14 days. That threshold was calibrated for batch. On an API service that handles 10x traffic spikes for 2-minute windows twice a day, P95 CPU will sit at 28% while the instance is actually at 90% CPU for those 2-minute windows. The flag fires. The recommendation says downsize. The engineer complies. Three weeks later, a traffic event hits and the incident queue lights up.

What P95 Hides: The 5% That Breaks Your SLO

P95 is not a flaw in the metric. It is exactly what the name says: the 95th percentile of CPU samples over the measurement window. By definition, it discards the top 5% of samples.

For a batch job, the top 5% is the tail of a job run. Ignoring it is fine.

For an API service with a 99.9% availability SLO, the top 5% of CPU samples is precisely when your latency SLOs are most at risk. Discarding it is exactly the wrong thing to do.

We routinely see workloads with P95 CPU at 28-32% that have P99.9 CPU spikes reaching 80-95% during traffic bursts, cache miss storms, or GC collection cycles. The instance looks idle at P95. It is not idle. It is bursting past its capacity for short windows that the percentile cut does not capture.

Architecture diagram

The actionable takeaway: any workload with a P99 CPU more than 2x its P95 CPU is burst-heavy. Using P95 to size it will cause a rollback.

The Burstable Instance Problem

T3 and T3a instances compound the P95 problem with a second layer of deception: CPU credits.

A T3.medium has a baseline CPU performance of 20% of 2 vCPUs. When the instance has accumulated credits, it can burst above that baseline. When credits are exhausted, the instance is throttled to 20% regardless of what the workload demands.

CloudWatch reports CPU utilization against the baseline-relative scale, not against absolute vCPU capacity. A T3.medium at 38% reported CPU utilization may be consuming credits at full burst rate. When the credit pool depletes, the instance drops to 20% effective CPU and the application latency spikes. CloudWatch still shows 20-25% CPU. Compute Optimizer still sees a comfortable utilization level. Nothing looks wrong until the application times out.

InstanceBaseline CPUBurst CPUCredit earn rateWhere the lie happens
t3.nano5%100%6 credits/hrReports 35% while at burst ceiling
t3.micro10%100%12 credits/hrAppears idle post-credit-exhaustion
t3.medium20%100%24 credits/hrCommon right-sizing false positive
t3.large30%100%36 credits/hrOverlaps with m5.large sizing decision

If your right-sizing analysis targets T3 instances without checking CPUSurplusCreditsCharged, you are flying blind. An instance spending $8/month on surplus credit charges is effectively an under-sized m5 instance that you are paying burstable prices for.

The fix for T3 instances: check CPUSurplusCreditsCharged in CloudWatch for the past 30 days before any downsizing decision. If the value is non-zero, do not downsize. Consider right-typing to a fixed-performance m5 instead.

The 4-Metric Recipe That Does Not Cause Rollbacks

P95 CPU is one metric. It measures one dimension of capacity. EC2 instances are constrained across four dimensions: CPU, memory, network, and application latency. Sizing on one dimension and ignoring the other three is how you get rollbacks.

We use four signals before any downsizing decision:

P99.9 CPU over a 14-day window. Not P95. Not P99. P99.9 captures the burst ceiling and is the correct signal for API services with latency SLOs. Threshold for downsizing action: P99.9 CPU below 60% for the full 14-day window.

P90 memory utilization over 7 days. CloudWatch does not report memory without the CloudWatch Agent. If you are not running the agent, deploy it before right-sizing anything. A workload that looks CPU-idle can be memory-bound: it spends cycles on GC and swap because it is running out of RAM, not CPU. P90 memory below 65% is required for a downsize to proceed.

Peak network throughput vs instance bandwidth limit. Each instance type has a documented network bandwidth ceiling. A c5.large with 10 Gbps bandwidth that regularly hits 9 Gbps is not over-provisioned for compute. It is correctly provisioned for network. Check NetworkIn + NetworkOut peak against the instance bandwidth limit.

Application p99 latency vs SLO. This is the ground truth signal. If p99 latency is within 20% of the SLO threshold, do not downsize regardless of what the infrastructure metrics say. The instance is doing exactly what the application needs.

SignalMeasurementDownsize thresholdWhat it catches that P95 misses
P99.9 CPU14-day windowBelow 60%Burst-heavy workloads with low median
P90 memory7-day windowBelow 65%Memory-bound services masking as CPU-idle
Peak network30-day maxBelow 70% of limitNetwork-saturated instances
App p99 latency14-day vs SLOAbove 20% headroomSLO-constrained instances that look idle

All four signals must clear their threshold before a downsize proceeds. One signal in the red is a hold.

The Resize Decision Framework

Not every under-utilized instance should be downsized to a smaller instance of the same type. Sometimes the correct move is to change the instance family.

If P99.9 CPU is below 60% and P90 memory is above 65%: the workload is memory-bound. Right-type to r5 or r6i instead of downsizing the compute. An m5.xlarge (4 vCPU, 16 GB RAM) running at 22% CPU but 80% memory should move to an r5.large (2 vCPU, 16 GB RAM), not an m5.large (2 vCPU, 8 GB RAM).

If P99.9 CPU is below 60% and p99 latency is within 20% of SLO: do not touch it. The instance is correctly sized for the latency requirement even if compute looks underused. This is the hardest recommendation to follow. The instance looks wasteful. It is not. It has latency headroom baked into its size.

If all four signals clear: downsize one size within the same family. Never skip two sizes in one step. A one-size move is recoverable in 10 minutes if something breaks. A two-size move that causes an incident takes 45 minutes to diagnose and roll back.

Architecture diagram

Right-sizing done correctly saves 20-35% on compute. The teams we work with who use all four signals see less than 5% rollback rate. The teams using P95 CPU alone see 40-60%. The 4-metric recipe takes 20 extra minutes to run. The avoided rollback takes 90 minutes to recover from. The math is straightforward.

P95 CPU is not a right-sizing signal. It is a batch job signal applied to workloads it was never designed for. The cloud cost anomaly detection patterns that catch overspend after the fact share the same root cause: the wrong metric driving the wrong decision. Use the signals that match your workload. Right-size once and stay sized.

Amanpreet Kaur

Written by

Amanpreet Kaur Author

Amanpreet works on Zop.Dev's cloud-cost engine, focused on commitment optimization and right-sizing across AWS, GCP, and Azure. She writes about Savings Plans vs RIs, break-even math, and the gnarly edges of multi-cloud cost data.

Tagged in

ZopDev Resources

Stay in the loop

Get the latest articles, ebooks, and guides
delivered to your inbox. No spam, unsubscribe anytime.