AWS costs can spiral out of control. After optimizing AWS spending for multiple organizations, here are strategies that reduce costs by 30-50%.

Cost Analysis

AWS Cost Explorer

# Enable Cost Explorer API
aws ce get-cost-and-usage \
  --time-period Start=2019-01-01,End=2019-01-31 \
  --granularity MONTHLY \
  --metrics BlendedCost

Cost by Service

# Get costs by service
aws ce get-cost-and-usage \
  --time-period Start=2019-01-01,End=2019-01-31 \
  --granularity MONTHLY \
  --metrics BlendedCost \
  --group-by Type=SERVICE

EC2 Optimization

Right-Sizing Instances

# Use CloudWatch metrics to analyze
aws cloudwatch get-metric-statistics \
  --namespace AWS/EC2 \
  --metric-name CPUUtilization \
  --dimensions Name=InstanceId,Value=i-1234567890abcdef0 \
  --start-time 2019-01-01T00:00:00Z \
  --end-time 2019-01-31T23:59:59Z \
  --period 3600 \
  --statistics Average,Maximum

Right-sizing strategy:

  • CPU < 20% → Downsize
  • CPU > 80% → Upsize
  • Memory < 20% → Use smaller instance
  • Network < 10% → Use smaller instance

Reserved Instances

# Purchase Reserved Instances
aws ec2 purchase-reserved-instances-offering \
  --reserved-instances-offering-id <offering-id> \
  --instance-count 10 \
  --limit-price Amount=1000.00,CurrencyCode=USD

Savings:

  • 1-year term: 30-40% savings
  • 3-year term: 50-60% savings
  • Convertible: More flexibility, less savings

Spot Instances

# Request spot instances
aws ec2 request-spot-instances \
  --spot-price "0.10" \
  --instance-count 5 \
  --type "one-time" \
  --launch-specification file://specification.json

Use cases:

  • Batch processing
  • CI/CD workloads
  • Data processing
  • Testing environments

Auto Scaling

# Create auto scaling group
aws autoscaling create-auto-scaling-group \
  --auto-scaling-group-name my-asg \
  --min-size 2 \
  --max-size 10 \
  --desired-capacity 4 \
  --launch-configuration-name my-launch-config \
  --vpc-zone-identifier "subnet-123,subnet-456"

Benefits:

  • Scale down during low traffic
  • Scale up during peak
  • 30-50% cost reduction

Storage Optimization

S3 Lifecycle Policies

{
  "Rules": [
    {
      "Id": "Move to Glacier",
      "Status": "Enabled",
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER"
        }
      ]
    },
    {
      "Id": "Delete old versions",
      "Status": "Enabled",
      "NoncurrentVersionTransitions": [
        {
          "NoncurrentDays": 30,
          "StorageClass": "GLACIER"
        }
      ],
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 365
      }
    }
  ]
}

EBS Optimization

# Use gp3 instead of gp2
aws ec2 create-volume \
  --volume-type gp3 \
  --size 100 \
  --iops 3000 \
  --throughput 125

# Delete unused snapshots
aws ec2 describe-snapshots \
  --owner-ids self \
  --query 'Snapshots[?StartTime<`2019-01-01`].[SnapshotId,StartTime]' \
  --output table

EBS Snapshot Cleanup

#!/bin/bash
# Delete snapshots older than 30 days
SNAPSHOTS=$(aws ec2 describe-snapshots \
  --owner-ids self \
  --query 'Snapshots[?StartTime<`'$(date -d '30 days ago' -u +%Y-%m-%dT%H:%M:%S)'`].SnapshotId' \
  --output text)

for snapshot in $SNAPSHOTS; do
  aws ec2 delete-snapshot --snapshot-id $snapshot
done

Database Optimization

RDS Right-Sizing

# Analyze RDS metrics
aws cloudwatch get-metric-statistics \
  --namespace AWS/RDS \
  --metric-name CPUUtilization \
  --dimensions Name=DBInstanceIdentifier,Value=mydb \
  --start-time 2019-01-01T00:00:00Z \
  --end-time 2019-01-31T23:59:59Z \
  --period 3600 \
  --statistics Average,Maximum

Optimization:

  • Use smaller instance types
  • Enable auto-scaling
  • Use read replicas for read-heavy workloads

DynamoDB Optimization

# Enable auto-scaling
aws application-autoscaling register-scalable-target \
  --service-namespace dynamodb \
  --resource-id table/my-table \
  --scalable-dimension dynamodb:table:ReadCapacityUnits \
  --min-capacity 5 \
  --max-capacity 100

Cost reduction:

  • Use on-demand billing for unpredictable workloads
  • Use provisioned capacity for predictable workloads
  • Enable TTL for automatic cleanup

Network Optimization

CloudFront Caching

# Create CloudFront distribution
aws cloudfront create-distribution \
  --distribution-config file://cloudfront-config.json

Benefits:

  • Reduced data transfer costs
  • Lower latency
  • Better user experience

VPC Endpoints

# Create VPC endpoint for S3
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-12345678 \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids rtb-12345678

Savings:

  • No data transfer charges
  • Reduced NAT Gateway costs

Monitoring and Alerts

Cost Anomaly Detection

# Create cost anomaly detector
aws ce create-anomaly-detector \
  --anomaly-detector-name cost-anomaly-detector \
  --anomaly-detector-type DIMENSIONAL \
  --monitor-dimension SERVICE

Budget Alerts

{
  "BudgetName": "monthly-budget",
  "BudgetLimit": {
    "Amount": "1000",
    "Unit": "USD"
  },
  "TimeUnit": "MONTHLY",
  "BudgetType": "COST",
  "CostFilters": {
    "Service": ["Amazon Elastic Compute Cloud - Compute"]
  },
  "CalculatedSpend": {
    "ActualSpend": {
      "Amount": "0",
      "Unit": "USD"
    }
  },
  "NotificationsWithSubscribers": [
    {
      "Notification": {
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 80
      },
      "Subscribers": [
        {
          "SubscriptionType": "EMAIL",
          "Address": "team@example.com"
        }
      ]
    }
  ]
}

Cost Optimization Checklist

Immediate Actions (Quick Wins)

  • Delete unused EBS volumes
  • Remove unattached elastic IPs
  • Clean up old snapshots
  • Delete unused load balancers
  • Terminate stopped instances
  • Remove unused security groups

Short-term (1-2 weeks)

  • Right-size EC2 instances
  • Purchase Reserved Instances
  • Implement S3 lifecycle policies
  • Enable auto-scaling
  • Use spot instances for batch jobs
  • Optimize RDS instance sizes

Long-term (1-3 months)

  • Migrate to newer instance types
  • Implement comprehensive monitoring
  • Set up cost budgets and alerts
  • Review and optimize architecture
  • Use serverless where appropriate
  • Implement cost allocation tags

Automation Scripts

Unused Resources Cleanup

import boto3

def cleanup_unused_resources():
    ec2 = boto3.client('ec2')
    
    # Find unattached volumes
    volumes = ec2.describe_volumes(
        Filters=[{'Name': 'status', 'Values': ['available']}]
    )
    
    for volume in volumes['Volumes']:
        age = (datetime.now() - volume['CreateTime']).days
        if age > 30:
            print(f"Deleting unused volume: {volume['VolumeId']}")
            ec2.delete_volume(VolumeId=volume['VolumeId'])
    
    # Find unattached elastic IPs
    addresses = ec2.describe_addresses()
    for address in addresses['Addresses']:
        if 'InstanceId' not in address:
            print(f"Releasing unattached IP: {address['PublicIp']}")
            ec2.release_address(AllocationId=address['AllocationId'])

Best Practices

  1. Monitor costs daily - Use Cost Explorer
  2. Set budgets - Alert on overspending
  3. Use tags - Track costs by project/team
  4. Right-size resources - Based on actual usage
  5. Use Reserved Instances - For predictable workloads
  6. Leverage spot instances - For flexible workloads
  7. Optimize storage - Lifecycle policies
  8. Review regularly - Monthly cost reviews

Expected Savings

  • Right-sizing: 20-30% reduction
  • Reserved Instances: 30-40% reduction
  • Storage optimization: 40-60% reduction
  • Auto-scaling: 30-50% reduction
  • Overall: 30-50% total reduction

Conclusion

AWS cost optimization requires:

  • Regular monitoring
  • Right-sizing resources
  • Using appropriate pricing models
  • Automating cleanup
  • Continuous review

Start with quick wins, then implement long-term strategies. The patterns shown here can reduce costs by 30-50%.


AWS cost optimization strategies from March 2019, covering practical cost reduction techniques.