Spot ve Preemptible Instance Kullanım Stratejileri

Bulut maliyetlerini düşürmenin en etkili yollarından biri, spot ve preemptible instance’ları akıllıca kullanmak. Ancak bu instance türlerini “ucuz diye açtım, çalıştı mı çalıştı” mantığıyla kullanırsanız, gecenin bir yarısı production sisteminizin çöktüğünü görürsünüz. Yıllar içinde edindiğim deneyimlere göre bu instance türlerini doğru stratejiyle kullanmak, AWS ya da GCP faturanızı %60-70 oranında düşürebilir. Ama yanlış kullanmak da o kadar kolay.

Spot ve Preemptible Instance Nedir, Ne Değildir?

Önce kavramları netleştirelim. AWS Spot Instance, Amazon’un kullanılmayan EC2 kapasitesini açık artırmayla (artık sabit fiyatla) sunduğu, normal fiyatın %90’a kadar altında olan instance türüdür. Google Cloud Preemptible VM ise benzer mantıkla çalışan, maksimum 24 saat çalışabilen ve Google’ın ihtiyaç duyduğunda 30 saniyelik uyarıyla sonlandırabileceği sanal makinelerdir. Azure’da bu konseptin karşılığı Spot Virtual Machines olarak geçiyor.

Bu instance’ların ortak özelliği şu: kapasite sağlayıcı bunları geri alabilir. Bu yüzden stateful, uzun süreli ve kesintiye tahammülü olmayan işler için bu instance türlerini kullanmak felakete davetiye çıkarmaktır.

Peki ne için kullanılabilir?

  • Batch işleme ve veri pipeline’ları
  • CI/CD build worker’ları
  • Makine öğrenmesi model eğitimi (checkpoint’li)
  • Video/resim işleme görevleri
  • Web crawling ve scraping işleri
  • Stateless mikro servis katmanları (uygun mimaride)
  • Test ortamları

AWS Spot Instance Stratejileri

Instance Fleet ile Çeşitlendirme

Tek bir instance türüne bağlı kalmak, spot kullanımında yapılan en büyük hatalardan biri. AWS, instance fleet özelliğiyle birden fazla instance tipi ve availability zone kombinasyonu belirlemenize olanak tanıyor. Böylece m5.xlarge kesildiğinde fleet otomatik olarak m5a.xlarge ya da m4.xlarge‘a geçiş yapıyor.

# Spot Fleet isteği oluşturma
aws ec2 request-spot-fleet 
  --spot-fleet-request-config '{
    "IamFleetRole": "arn:aws:iam::123456789:role/SpotFleetRole",
    "TargetCapacity": 10,
    "AllocationStrategy": "diversified",
    "LaunchSpecifications": [
      {
        "ImageId": "ami-0abcdef1234567890",
        "InstanceType": "m5.xlarge",
        "SubnetId": "subnet-11111111"
      },
      {
        "ImageId": "ami-0abcdef1234567890",
        "InstanceType": "m5a.xlarge",
        "SubnetId": "subnet-22222222"
      },
      {
        "ImageId": "ami-0abcdef1234567890",
        "InstanceType": "m4.xlarge",
        "SubnetId": "subnet-33333333"
      }
    ]
  }'

diversified stratejisi, kapasiteyi farklı pool’lara dağıtıyor. lowestPrice stratejisi ise sadece en ucuz pool’u kullanıyor ama kesilme riskini artırıyor. Production benzeri ortamlarda her zaman diversified kullanın.

Interruption Notice’ı Yakalamak

AWS, bir spot instance’ı sonlandırmadan 2 dakika önce uyarı veriyor. Bu süreyi değerlendirmek hayat kurtarıcı. EC2 instance metadata servisinden bu uyarıyı polling ile yakalayabilirsiniz.

#!/bin/bash
# spot_monitor.sh - Spot interruption izleme scripti

METADATA_URL="http://169.254.169.254/latest/meta-data/spot/interruption-action"
CHECKPOINT_DIR="/var/checkpoints"
LOG_FILE="/var/log/spot_monitor.log"

check_interruption() {
    HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" 
        --connect-timeout 2 
        "$METADATA_URL")
    
    if [ "$HTTP_CODE" == "200" ]; then
        echo "$(date): UYARI - Spot instance kesilecek!" >> "$LOG_FILE"
        
        # Uygulamayı graceful shutdown için sinyal gönder
        pkill -SIGTERM -f "myapp"
        
        # Checkpoint kaydet
        cp -r /var/app/state "$CHECKPOINT_DIR/$(date +%s)/"
        
        # SQS kuyruğuna mesaj gönder (başka bir instance devam etsin)
        aws sqs send-message 
            --queue-url "https://sqs.us-east-1.amazonaws.com/123456789/spot-failover" 
            --message-body '{"action": "resume", "checkpoint": "/checkpoints/latest"}'
        
        echo "$(date): Checkpoint kaydedildi, failover başlatıldı" >> "$LOG_FILE"
    fi
}

# Her 30 saniyede bir kontrol et
while true; do
    check_interruption
    sleep 30
done

Bu scripti systemd servisi olarak çalıştırın ve instance başladığında otomatik devreye girsin.

# /etc/systemd/system/spot-monitor.service
cat > /etc/systemd/system/spot-monitor.service << 'EOF'
[Unit]
Description=Spot Instance Interruption Monitor
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/spot_monitor.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

systemctl enable spot-monitor
systemctl start spot-monitor

Spot Price History Analizi

Hangi instance tipinin daha az kesildiğini anlamak için spot price history’yi analiz etmek gerekiyor. Fiyat dalgalanması az olan instance tipler, genellikle kesilme sıklığı da düşük olan tiplerdir.

# Son 7 günlük spot fiyat geçmişini çek
aws ec2 describe-spot-price-history 
  --instance-types m5.xlarge m5a.xlarge m4.xlarge 
  --product-descriptions "Linux/UNIX" 
  --start-time $(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%S) 
  --query 'SpotPriceHistory[*].{Type:InstanceType,AZ:AvailabilityZone,Price:SpotPrice,Time:Timestamp}' 
  --output json | python3 -c "
import json, sys
from collections import defaultdict

data = json.load(sys.stdin)
prices = defaultdict(list)

for item in data:
    key = f"{item['Type']} / {item['AZ']}"
    prices[key].append(float(item['Price']))

for combo, price_list in sorted(prices.items()):
    avg = sum(price_list) / len(price_list)
    variance = max(price_list) - min(price_list)
    print(f'{combo}: Ort={avg:.4f}, Dalgalanma={variance:.4f}')
"

Google Cloud Preemptible VM Stratejileri

Preemptible VM ile Managed Instance Group

GCP’de preemptible instance kullanmanın en sağlam yolu, Managed Instance Group (MIG) ile birleştirmektir. MIG, sonlanan instance’ları otomatik yeniden başlatır.

# Instance template oluştur (preemptible ile)
gcloud compute instance-templates create spot-worker-template 
  --machine-type=n1-standard-4 
  --image-family=debian-11 
  --image-project=debian-cloud 
  --preemptible 
  --boot-disk-size=50GB 
  --metadata-from-file startup-script=startup.sh 
  --scopes=cloud-platform

# Managed Instance Group oluştur
gcloud compute instance-groups managed create spot-worker-group 
  --template=spot-worker-template 
  --size=5 
  --zone=us-central1-a

# Autoscaling ekle
gcloud compute instance-groups managed set-autoscaling spot-worker-group 
  --zone=us-central1-a 
  --min-num-replicas=2 
  --max-num-replicas=20 
  --target-cpu-utilization=0.7 
  --cool-down-period=60

Preemption Sinyalini Yakalamak

GCP’de preemption sinyali ACPI g2 soft-off eventi olarak geliyor. Bunu shutdown script ile yakalayabilirsiniz.

#!/bin/bash
# /etc/preemption-handler.sh
# GCP metadata'dan preemption uyarısını izle

METADATA_BASE="http://metadata.google.internal/computeMetadata/v1"
HEADERS="-H 'Metadata-Flavor: Google'"

# Preemption zamanını izle (long polling)
monitor_preemption() {
    curl -s 
        -H "Metadata-Flavor: Google" 
        "${METADATA_BASE}/instance/preempted?wait_for_change=true&last_etag=0&timeout_sec=60"
    
    local result=$?
    if [ $result -eq 0 ]; then
        echo "$(date): Preemption sinyali alındı!"
        
        # Çalışan job'ı checkpoint'e al
        if pgrep -f "training_job.py" > /dev/null; then
            kill -USR1 $(pgrep -f "training_job.py")
            sleep 10
        fi
        
        # Durumu GCS'e kaydet
        gsutil -m cp -r /var/app/checkpoints gs://my-bucket/checkpoints/$(hostname)/
        
        # Pub/Sub'a bildir
        gcloud pubsub topics publish job-status 
            --message='{"status": "preempted", "host": "'"$(hostname)"'", "time": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"}'
    fi
}

while true; do
    monitor_preemption
    sleep 5
done

Karma Mimari: On-Demand + Spot/Preemptible

Tamamen spot tabanlı sistemler riskli olduğu için production’da karma mimari kullanmak en doğrusu. Minimum kapasiteyi on-demand ile karşılayıp, yük arttığında spot ile scale ediyorsunuz.

# AWS EKS için node group yapılandırması
# eksctl ile spot + on-demand karma cluster

cat > cluster-config.yaml << 'EOF'
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: production-cluster
  region: us-east-1

nodeGroups:
  # On-demand baseline (kritik servisler için)
  - name: on-demand-baseline
    instanceType: m5.xlarge
    desiredCapacity: 3
    minSize: 2
    maxSize: 5
    labels:
      node-type: on-demand
    taints:
      - key: node-type
        value: on-demand
        effect: NoSchedule

  # Spot worker pool (batch ve scale işleri için)
  - name: spot-workers
    instancesDistribution:
      maxPrice: 0.08
      instanceTypes:
        - m5.xlarge
        - m5a.xlarge
        - m4.xlarge
        - m5d.xlarge
      onDemandBaseCapacity: 0
      onDemandPercentageAboveBaseCapacity: 0
      spotAllocationStrategy: diversified
    desiredCapacity: 5
    minSize: 0
    maxSize: 50
    labels:
      node-type: spot
EOF

eksctl create cluster -f cluster-config.yaml

Kubernetes’te Spot Instance Yönetimi

Kubernetes ortamında spot kullanmak ayrı bir sanat. Pod’larınızı doğru şekilde yapılandırmazsanız, node kesildiğinde uzun süre recovery beklentisiyle karşılaşabilirsiniz.

Pod Disruption Budget ve Tolerations

# Spot node'lara tolerations ekle
cat > spot-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: batch-processor
spec:
  replicas: 10
  selector:
    matchLabels:
      app: batch-processor
  template:
    metadata:
      labels:
        app: batch-processor
    spec:
      # Spot node tercih et ama zorla değil
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            preference:
              matchExpressions:
              - key: node-type
                operator: In
                values:
                - spot
      tolerations:
      - key: "spot-instance"
        operator: "Equal"
        value: "true"
        effect: "NoSchedule"
      # Graceful shutdown için terminationGracePeriod
      terminationGracePeriodSeconds: 90
      containers:
      - name: processor
        image: myapp:latest
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
          limits:
            cpu: "1000m"
            memory: "1Gi"
        # SIGTERM handler'ı aktif et
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 10 && /app/graceful-shutdown.sh"]
---
# Pod Disruption Budget - minimum %50 hazır olsun
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: batch-processor-pdb
spec:
  minAvailable: 5
  selector:
    matchLabels:
      app: batch-processor
EOF

kubectl apply -f spot-deployment.yaml

AWS Node Termination Handler

Kubernetes cluster’ınızda AWS Node Termination Handler kurarak spot interruption event’lerini otomatik yönetebilirsiniz.

# Helm ile AWS Node Termination Handler kurulumu
helm repo add eks https://aws.github.io/eks-charts
helm repo update

helm install aws-node-termination-handler 
  eks/aws-node-termination-handler 
  --namespace kube-system 
  --set enableSpotInterruptionDraining=true 
  --set enableScheduledEventDraining=true 
  --set enableRebalanceMonitoring=true 
  --set enableSqsTerminationDraining=true 
  --set queueURL=https://sqs.us-east-1.amazonaws.com/123456789/nth-queue 
  --set logLevel=info

Maliyet Optimizasyonu: Gerçek Dünya Senaryosu

Bir e-ticaret müşterisinin video thumbnail oluşturma pipeline’ını spot instance’lara taşıdığımda yaşadıklarım iyi bir örnek. Önceki yapıda 10 adet c5.2xlarge on-demand instance 7/24 çalışıyordu. Aylık maliyet yaklaşık 2.800 dolar.

Yeni yapıda:

  • 2 adet on-demand c5.xlarge (koordinasyon ve SQS tüketici)
  • 8-20 adet spot c5.2xlarge (iş yüküne göre auto-scale)
  • SQS kuyruğu (işler kaybolmasın diye)
  • S3’te checkpoint mekanizması

Aylık maliyet: yaklaşık 750-900 dolar. Yüzde 68 tasarruf.

Burada kritik nokta şu: iş birimleri idempotent olmalı. Bir video işleme job’ı kesildiğinde, başka bir instance aynı job’ı alıp baştan başlatmalı ve sonuç aynı olmalı. Bunun için her video işinin durumunu DynamoDB’de tutuyorduk.

# DynamoDB'de job state yönetimi
# Job başladığında "processing" yap
aws dynamodb update-item 
  --table-name video-jobs 
  --key '{"job_id": {"S": "'$JOB_ID'"}}' 
  --update-expression "SET #s = :processing, worker_id = :wid, started_at = :ts" 
  --condition-expression "#s = :pending" 
  --expression-attribute-names '{"#s": "status"}' 
  --expression-attribute-values '{
    ":processing": {"S": "processing"},
    ":pending": {"S": "pending"},
    ":wid": {"S": "'$(hostname)'"},
    ":ts": {"S": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}
  }' 
  --return-values NONE 2>/dev/null

# Eğer conditional check başarısız olduysa başka worker almış demek
if [ $? -ne 0 ]; then
    echo "Job $JOB_ID başka bir worker tarafından alınmış, atlanıyor."
    exit 0
fi

Spot Instance için Monitoring ve Alerting

Spot kesintilerini izlemek için CloudWatch Events kullanabilirsiniz. Bu sayede kaç tane kesinti yaşandığını, hangi instance tiplerinde sorun çıktığını takip edebilirsiniz.

# CloudWatch'a spot interruption metriği gönder
aws cloudwatch put-metric-data 
  --namespace "SpotInstances" 
  --metric-data '[
    {
      "MetricName": "InterruptionCount",
      "Dimensions": [
        {"Name": "InstanceType", "Value": "m5.xlarge"},
        {"Name": "AvailabilityZone", "Value": "us-east-1a"}
      ],
      "Value": 1,
      "Unit": "Count"
    }
  ]'

# Alarm kur: 1 saatte 3'ten fazla kesinti olursa uyar
aws cloudwatch put-metric-alarm 
  --alarm-name "SpotInterruptionHigh" 
  --alarm-description "Spot kesinti orani yuksek" 
  --metric-name "InterruptionCount" 
  --namespace "SpotInstances" 
  --statistic Sum 
  --period 3600 
  --threshold 3 
  --comparison-operator GreaterThanOrEqualToThreshold 
  --evaluation-periods 1 
  --alarm-actions arn:aws:sns:us-east-1:123456789:ops-alerts

Yaygın Hatalar ve Kaçınma Yolları

Tek AZ’de spot kullanmak: Bir availability zone’daki kapasite bittiğinde tüm spot instance’larınız kesilir. Her zaman çoklu AZ kullanın.

Stateful uygulamaları doğrudan spot’a taşımak: Veritabanı, cache veya oturum bilgisi tutan uygulamaları spot’a almadan önce state’i dışarı çıkarın. Redis, RDS, DynamoDB gibi managed servisler burada yardımcı olur.

Max price belirlememek: AWS spot’ta max fiyat belirlememek, beklenmedik maliyet artışlarına yol açabilir. Spot fiyatı on-demand fiyatına yaklaştığında ne yapacağınızı önceden belirleyin.

Checkpointing yapmadan uzun süren joblar çalıştırmak: 6 saatlik bir ML eğitimini checkpoint’siz spot’ta çalıştırmak riskli. En az 30 dakikada bir checkpoint alın.

Instance tipine çok bağımlı olmak: Belirli bir instance tipine özel optimizasyon yapmak (örneğin sadece AVX-512 için), farklı instance tipine fallback yaparken sorun çıkarır.

Hangi İş Yükleri İçin Kesinlikle Kullanmayın

  • Primary veritabanları (okuma replikaları için düşünülebilir ama dikkatli olun)
  • Real-time ödeme işleme sistemleri
  • WebSocket bağlantıları tutan uygulamalar (bağlantı kopması kabul edilemez olan)
  • Tek node’da çalışan kritik monitoring sistemleri
  • License sunucuları (çoğu lisans sistemi instance değişikliğine duyarlıdır)

Sonuç

Spot ve preemptible instance’lar, doğru kullanıldığında bulut faturanızı dramatik biçimde düşüren güçlü araçlar. Ancak bu araçları kullanmak için uygulama mimarinizi buna göre tasarlamanız şart. Kesintilere dayanıklı, idempotent iş birimleri, düzgün checkpoint mekanizmaları ve çoklu instance tipi stratejileri olmadan spot kullanmak, zaman kazanmak yerine zaman kaybettirir.

Başlangıç için şu adımları takip edin: önce mevcut iş yüklerinizi analiz edin ve hangilerinin kesintiye toleranslı olduğunu belirleyin, batch ve CI/CD pipeline’larından başlayın, monitoring ve alerting kurun, ardından yavaş yavaş daha fazla iş yükünü spot’a taşıyın. Acele etmeyin, her adımda ne kadar tasarruf ettiğinizi ve kaç kesinti yaşadığınızı ölçün. Zaman içinde hangi kombinasyonun sizin iş yükleri için en iyi çalıştığını göreceksiniz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir