CloudFinOps logo
CloudFinOps
Cloud Cost Optimization

Autoscaling vs Rightsizing: Your Resource Isn't Idle, It's Just Sleeping

Nishant Jain

Nishant Jain

Co-Founder & CTO · · 12 min read

The Point-in-Time Problem

It's 3 AM. A FinOps tool scans your infrastructure. It sees a VM running at 4% CPU. The recommendation: "This resource is idle. Consider downsizing or terminating."

At 10 AM, that same VM handles 2,000 requests per second and runs at 78% CPU. It powers your checkout flow. If you'd followed that 3 AM recommendation, your customers would get 503 errors during peak hours.

This is the fundamental flaw in most cloud optimization tools: they take a point-in-time snapshot and make a recommendation based on that single measurement. It's like measuring someone's heart rate while they sleep and diagnosing them as having dangerously low cardiac output.

Real workloads have patterns. Some spike during business hours and idle at night. Some burst on weekdays and flatline on weekends. Some have monthly peaks around billing cycles or quarterly spikes during reporting. A single measurement tells you nothing about the right optimization action.

The Three Types of Workload Patterns

After analyzing thousands of cloud resources, workload utilization falls into one of five patterns. Each pattern requires a different optimization strategy:

Pattern 1: Diurnal (Day/Night Cycle)

What it looks like: High utilization during business hours (8 AM to 8 PM), low utilization overnight and weekends.

Example: Web application serving users in a single timezone. B2B SaaS product used during working hours. Internal tools accessed by office employees.

Key metric: Peak-to-trough ratio > 2.5x (e.g., 70% peak vs 10% trough)

Correct optimization: AUTOSCALE, not rightsize.

If you rightsize this VM to handle the average load, you'll crash during peak. If you keep it provisioned for peak, you waste money 16 hours/day. The correct answer is autoscaling that adds capacity during peak and removes it during trough.

Pattern 2: Steady State (Flat Line)

What it looks like: Consistent utilization 24/7. Doesn't matter what time of day or which day of week. CPU stays between 30-50% (or 5-15%) all the time.

Example: Background queue processors. Database replicas. Cache servers. API gateways with global traffic.

Key metric: Coefficient of variation < 0.3 (low variance relative to mean)

Correct optimization: RIGHTSIZE.

If a VM consistently runs at 15% CPU with no peaks, it's genuinely over-provisioned. Downsize it. If it consistently runs at 40%, it's well-sized. Leave it alone. The stability of the pattern means a point-in-time measurement actually IS representative.

Pattern 3: Burst/Sporadic (Mostly Idle, Occasional Spikes)

What it looks like: 80%+ of the time near zero. Occasional bursts to 60-90% lasting minutes to hours. Unpredictable timing.

Example: CI/CD build servers. Batch processing jobs triggered by events. Data pipeline workers. ML inference endpoints with variable traffic.

Key metric: P50 < 10%, P99 > 50% (idle most of the time, intense during bursts)

Correct optimization: SPOT INSTANCES or SERVERLESS.

This workload doesn't need a permanently provisioned VM. It needs capacity on demand. Use Azure Spot VMs (60-90% discount, accept 30-second eviction notice), AWS Spot Fleet, or move to serverless (Azure Functions, AWS Lambda, Cloud Run) where you pay only for actual execution time.

Pattern 4: Weekly Cycle

What it looks like: Active on weekdays, dead on weekends. Or the reverse (media/entertainment workloads peak on weekends).

Example: Enterprise B2B applications. Payroll processing. Internal analytics dashboards.

Key metric: Weekday average > 2x weekend average

Correct optimization: SCHEDULE.

Stop the resource on Friday evening, start it Monday morning. You save ~28% of the monthly cost (2 out of 7 days) with zero risk to weekday operations. AWS Instance Scheduler and Azure Auto-shutdown handle this natively.

Pattern 5: Growing (Upward Trend)

What it looks like: Utilization has been climbing steadily over weeks. What was 30% a month ago is now 55% and still rising.

Example: Applications gaining users. Data volumes growing. Feature additions increasing baseline load.

Key metric: Trend slope > 5% increase per week over 14+ days

Correct optimization: AUTOSCALE NOW (preventive).

This workload will hit capacity limits soon. Don't wait for it to crash. Set up autoscaling proactively with the current load as the baseline and 2-3x as the ceiling. This is cheaper than an emergency over-provision after an outage.

The Decision Matrix

ConditionRecommendationWhy
Peak/trough ratio > 2.5x, repeating dailyAutoscaleNeeds capacity elasticity, not a fixed size
Steady utilization < 25%, no peaks above 40%Rightsize downGenuinely over-provisioned
Steady utilization 25-70%, no concerning peaksNo actionWell-sized for its workload
Idle 80%+ of time, rare burst spikesSpot/ServerlessPaying for idle capacity you rarely use
Weekday > 2x weekend utilizationSchedule (stop weekends)Pay for 5 days instead of 7
Trending upward > 5%/weekAutoscale (proactive)Will hit limits soon
Under 5% CPU, < 1MB network, 14+ daysActually idle (zombie)Terminate or investigate

The critical insight: only the last row is a true "idle" resource. Everything else is a workload pattern that requires a specific, different action.

See how much you're wasting

Get a free 7-day cloud audit. No credit card, no agents, read-only access.

Start Free Audit

How to Detect Patterns: The 30-Day Signal Method

A single metric check tells you nothing. You need 30 days of hourly data to classify a workload pattern. Here's why:

  • 7 days catches daily patterns but misses weekly cycles
  • 14 days catches weekly patterns but can't distinguish steady trends from temporary spikes
  • 30 days gives you 4 full weekly cycles, reveals monthly patterns, and provides enough data for statistical confidence

What to Measure

CPU alone is not enough. A full picture requires:

MetricWhat It Tells YouTool Example
CPU (average + P95)Compute demand patternCloudWatch, Azure Monitor
Memory (average + P95)Working set size; cache vs compute workloadCloudWatch agent, Azure VM Insights
Network In/OutTraffic pattern; often correlates with user demandVPC Flow Logs, NSG Flow Logs
Disk IOPSStorage-bound vs compute-boundEBS metrics, Managed Disk metrics
Connection countActive users or service dependenciesLoad balancer metrics

Multi-signal classification:

CPUMemoryNetworkClassification
LowLowLowZombie (all signals agree)
LowHighLowMemory workload (cache/in-memory DB). Do NOT downsize.
LowLowHighNetwork proxy/gateway. Do NOT terminate.
DiurnalDiurnalDiurnalApplication with user traffic. Autoscale.
Low average, high P95StableBurstyBatch processor. Use spot or serverless.

How to Set Up Autoscaling Correctly

Most teams set up autoscaling with default thresholds and wonder why it doesn't work. The defaults (70% scale-out, 30% scale-in on AWS) are reasonable starting points, but optimal thresholds depend on your workload's response time requirements.

Computing the Right Thresholds

Scale-out threshold (when to add capacity):

Take your P90 CPU utilization during normal peak hours. That's your "comfortable operating point." Set scale-out at 80% of that value.

Example: Peak hours run at 65% CPU average. Scale-out threshold = 65% × 0.8 = 52%.

Why 80%? Because by the time the autoscaler detects the threshold breach, launches a new instance, and the instance passes health checks (typically 2-5 minutes), your existing instances need headroom to handle the traffic that arrived during that scaling delay.

Scale-in threshold (when to remove capacity):

Set this at the P25 of your trough utilization. You want to be conservative about removing capacity because scaling down too aggressively causes flip-flopping (scale out, scale in, scale out, scale in).

Example: Trough hours run at 15% CPU. Scale-in threshold = 15% (P25 of trough).

Cooldown period:

Minimum 5 minutes between scaling actions. This prevents flip-flopping. AWS uses 300 seconds default; GCP uses 600 seconds (10 minutes). For most workloads, 5 minutes is correct. For slowly-warming applications (JVM, large ML models), use 10-15 minutes.

Min and Max Instance Count

Minimum instances: Must handle your trough load + one instance failure. If trough load needs 1 instance, set min to 2 (fault tolerance). If trough needs 3, set min to 4.

Maximum instances: Must handle your historical peak + 30% buffer for growth. If peak has historically needed 8 instances, set max to 10-12.

Don't set max too high. A runaway autoscaler during a traffic spike or DDoS can scale to 50 instances before anyone notices. Set a realistic maximum and alert if it's reached.

The Rightsizing Methodology (When It IS Appropriate)

For workloads that are genuinely steady-state (Pattern 2), rightsizing is straightforward:

  1. Collect P95 CPU and memory for 30 days
  2. Target 60-70% utilization at the new instance size (P95 should be 60-70% of the new instance's capacity)
  3. Validate with P99 (must stay below 85% of new capacity; otherwise you'll have occasional performance issues)
  4. Step down one size at a time (don't jump from xlarge to small; go xlarge → large → medium over 2-3 weeks)
  5. Monitor for 7 days after each step-down before continuing

Instance family selection matters too:

Your P95 PatternCurrent InstanceRecommended Family
High CPU, low memoryGeneral purpose (m5)Compute-optimized (c5) - more CPU per dollar
Low CPU, high memoryGeneral purpose (m5)Memory-optimized (r5) - more RAM per dollar
Both highGeneral purpose (m5)Stay general purpose, just resize
Very low bothLarge instanceBurstable (t3) - cheapest for low utilization

Real-World Example: A B2B SaaS Application

A team runs their API on 3x Standard_D4s_v3 (Azure) at $140/month each ($420/month total).

A basic optimization tool says: "Average CPU is 18%. Rightsize to D2s_v3."

But the 30-day analysis reveals:

  • Peak hours (9 AM - 6 PM IST): 62% average CPU, P95 = 78%
  • Off hours (6 PM - 9 AM): 4% average CPU
  • Weekends: 2% average CPU
  • Pattern: Diurnal + Weekly

The correct recommendation:

  1. Enable Azure Virtual Machine Scale Sets (autoscaling)
  2. Min instances: 1 (handles off-hours/weekend traffic)
  3. Max instances: 4 (handles peak with 30% buffer)
  4. Scale-out at 55% CPU, scale-in at 20% CPU
  5. Result: runs 1 instance for 14 hours/day + weekends, 3-4 instances for 10 peak hours

Cost before: $420/month (3 instances 24/7) Cost after: ~$185/month (autoscaled) Savings: $235/month (56% reduction) without any performance impact

If they'd followed the "rightsize to D2s_v3" recommendation instead: $210/month but with P95 CPU at 156% during peak (application crashes).

FAQ

How long should I collect data before making an optimization decision?

30 days minimum for any change. 7 days is not enough because you'll miss weekly patterns and monthly spikes. 14 days gives you a partial picture but can be thrown off by holidays or unusual events. 30 days captures 4 full weekly cycles and provides statistical confidence for pattern classification.

Can I use both autoscaling and rightsizing together?

Yes, and you should. First, rightsize the instance type that your autoscaler uses (the launch template). If your autoscaler launches m5.2xlarge instances but each instance only needs m5.large capacity, fix the template. Then the autoscaler adds smaller, cheaper instances during peaks.

What about memory-based autoscaling? My app doesn't use much CPU but needs RAM.

Most cloud autoscalers support custom metrics. On AWS, publish memory utilization to CloudWatch via the CloudWatch agent, then create a target tracking policy on that metric. On Azure, Virtual Machine Scale Sets can scale on custom Application Insights metrics. Memory-based scaling is correct for JVM applications, caches, and in-memory databases.

Is autoscaling worth it if my peak is only 2x my trough?

Yes if the cost difference justifies the setup effort. A 2x ratio means you're paying 50% more than necessary during off-peak. For a $500/month instance, that's $250/month in potential savings. Autoscaling setup takes 2-4 hours. Payback period: less than 1 month.

My application takes 5 minutes to start. Does autoscaling still work?

Yes, but you need to configure the instance warmup period accordingly. Set warmup to 5-7 minutes so the autoscaler doesn't count still-booting instances in its capacity calculation. Also consider: predictive scaling (AWS has this), which pre-warms instances 5-10 minutes before the predicted spike based on historical patterns. For applications with very long startup times (15+ minutes), pre-warming on a cron schedule might be more reliable than reactive autoscaling.

Related articles