AWS Reserved Capacity Planning Strategies
Develop effective Reserved Instance and Savings Plans strategies to maximize AWS cost savings while maintaining flexibility.
Reserved capacity commitments can reduce AWS costs by up to 72%, but require careful planning to avoid overcommitment and maintain flexibility.
Understanding Commitment Options
Reserved Instances vs Savings Plans
| Feature | Reserved Instances | Savings Plans |
|---|---|---|
| Flexibility | Instance-specific | Usage-based |
| Discount | Up to 72% | Up to 72% |
| Scope | Regional/Zonal | Account/Organization |
| Convertibility | Standard/Convertible | Compute/EC2 |
Usage Analysis
Identify Baseline Usage
import boto3
from datetime import datetime, timedelta
ce = boto3.client('ce')
def analyze_ec2_usage(months=6):
end = datetime.now()
start = end - timedelta(days=months * 30)
response = ce.get_cost_and_usage(
TimePeriod={
'Start': start.strftime('%Y-%m-%d'),
'End': end.strftime('%Y-%m-%d')
},
Granularity='DAILY',
Metrics=['UsageQuantity', 'UnblendedCost'],
GroupBy=[
{'Type': 'DIMENSION', 'Key': 'INSTANCE_TYPE'},
{'Type': 'DIMENSION', 'Key': 'REGION'}
],
Filter={
'Dimensions': {
'Key': 'SERVICE',
'Values': ['Amazon Elastic Compute Cloud - Compute']
}
}
)
return analyze_patterns(response['ResultsByTime'])
def analyze_patterns(results):
usage_by_type = {}
for day in results:
for group in day['Groups']:
instance_type = group['Keys'][0]
region = group['Keys'][1]
hours = float(group['Metrics']['UsageQuantity']['Amount'])
key = f"{instance_type}|{region}"
if key not in usage_by_type:
usage_by_type[key] = []
usage_by_type[key].append(hours)
# Calculate baseline (10th percentile) and average
recommendations = []
for key, hours in usage_by_type.items():
instance_type, region = key.split('|')
baseline = sorted(hours)[len(hours) // 10] # 10th percentile
average = sum(hours) / len(hours)
recommendations.append({
'instance_type': instance_type,
'region': region,
'baseline_daily_hours': baseline,
'average_daily_hours': average,
'recommended_ri_count': int(baseline / 24)
})
return recommendations
Coverage Analysis
def get_reservation_coverage():
response = ce.get_reservation_coverage(
TimePeriod={
'Start': (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'),
'End': datetime.now().strftime('%Y-%m-%d')
},
Granularity='MONTHLY',
GroupBy=[
{'Type': 'DIMENSION', 'Key': 'INSTANCE_TYPE'}
]
)
coverage_report = []
for group in response['CoveragesByTime'][0]['Groups']:
coverage = group['Coverage']['CoverageHours']
coverage_report.append({
'instance_type': group['Attributes']['instanceType'],
'covered_hours': float(coverage['CoverageHoursPercentage']),
'on_demand_hours': float(coverage['OnDemandHours']),
'reserved_hours': float(coverage['ReservedHours'])
})
return coverage_report
Savings Plans Strategy
Compute Savings Plans
def purchase_compute_savings_plan(commitment_usd, term_years=1):
sp = boto3.client('savingsplans')
# Get offering
offerings = sp.describe_savings_plans_offerings(
paymentOptions=['NO_UPFRONT'],
planTypes=['COMPUTE_SAVINGS_PLAN'],
productType='Compute',
currencies=['USD'],
durations=[term_years * 31536000] # Seconds in year
)
# Select offering
offering = offerings['searchResults'][0]
# Purchase
response = sp.create_savings_plan(
savingsPlanOfferingId=offering['offeringId'],
commitment=str(commitment_usd),
purchaseTime=datetime.now().isoformat()
)
return response
Layered Commitment Strategy
CommitmentStrategy:
Layer1_Baseline:
Type: 3-Year No Upfront Compute Savings Plan
Coverage: 50% of baseline
Discount: ~66%
Layer2_Stable:
Type: 1-Year Convertible RI
Coverage: Next 25% of stable workloads
Discount: ~40%
Layer3_OnDemand:
Type: On-Demand + Spot
Coverage: Remaining variable workloads
Flexibility: Maximum
Monitoring and Optimization
Utilization Tracking
def monitor_commitment_utilization():
# Check RI utilization
ri_utilization = ce.get_reservation_utilization(
TimePeriod={
'Start': (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'),
'End': datetime.now().strftime('%Y-%m-%d')
},
GroupBy=[
{'Type': 'DIMENSION', 'Key': 'SUBSCRIPTION_ID'}
]
)
# Check Savings Plans utilization
sp_utilization = ce.get_savings_plans_utilization(
TimePeriod={
'Start': (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'),
'End': datetime.now().strftime('%Y-%m-%d')
}
)
return {
'ri_utilization': ri_utilization,
'sp_utilization': sp_utilization
}
Working with Warqline
We are a cloud engineering consultancy and an official AWS and Google Cloud partner. If you are running this in production and want a second pair of eyes, we scope work in a free 45-minute technical call: you describe what you are running and what worries you, and we tell you what we would look at first.
Conclusion
Effective reserved capacity planning balances cost savings with flexibility. Use a layered approach, regularly monitor utilization, and adjust commitments based on evolving workload patterns.