Ana içeriğe geç

Capacity Planning — "Ne Kadar Yeterli?" Sorusunun Mühendislik Cevabı#

"Yeterli kapasite 'sezgi' değil — veri ile kanıtlanır. 'Şimdiye kadar yetmişti' deyen ekip, Black Friday'de bu yıl da yeter mi? sorusuna cevap veremez. Capacity = bilinç + plan."

Bu rehber demand forecasting, headroom hesaplama, load test framework'ü ve "ne zaman scale up?" sorusunun yöntemsel cevabını verir.


🎯 Capacity Planning — 3 Soru#

1. Şu an ne kadar kapasitemiz var?         (mevcut)
2. Talep ne kadar büyüyor?                  (forecast)
3. Hangi kaynak ne zaman bitecek?           (saturation point)

📊 Mevcut Kapasiteyi Ölçme#

CPU saturation#

# CPU utilization (avg)
1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m]))

# Per-pod CPU
sum(rate(container_cpu_usage_seconds_total[5m])) by (pod)
/
sum(kube_pod_container_resource_limits{resource="cpu"}) by (pod)

Memory#

# Pod memory usage / limit
sum(container_memory_working_set_bytes) by (pod)
/
sum(kube_pod_container_resource_limits{resource="memory"}) by (pod)

Disk#

# Disk usage trend
node_filesystem_avail_bytes / node_filesystem_size_bytes

Connection / Request rate#

# Request per second
sum(rate(http_requests_total[5m]))

# DB connection
pg_stat_activity_count / pg_settings_max_connections

📈 Demand Forecasting#

Linear projection#

# Disk dolacak mı? 30 gün için tahmin
predict_linear(node_filesystem_avail_bytes[6h], 30*24*3600) < 0

Seasonality (Holt-Winters)#

  • Günlük pattern: gece düşük, gündüz yüksek
  • Haftalık: hafta sonu düşük (B2B SaaS) veya yüksek (B2C)
  • Yıllık: Black Friday, Ramadan, Christmas
import statsmodels.tsa.holtwinters as hw

# Aylık request count → 6 ay forecast
model = hw.ExponentialSmoothing(
    monthly_requests,
    trend='add',
    seasonal='add',
    seasonal_periods=12
).fit()

forecast = model.forecast(6)

Business growth#

  • Marketing campaign → +%30 traffic
  • Yeni feature launch → unknown spike
  • Müşteri segment growth: per-customer scenario

🔑 Forecast = istatistik + business. İkisini de değerlendir.


🎯 Headroom Hedefi#

Resource Hedef Headroom Niye
CPU %30+ boş Spike + GC + retry overhead
Memory %20+ boş OOM tampon
Disk %30+ boş WAL + backup + log büyüme
DB connection %50+ boş Connection storm tampon
Network bandwidth %40+ boş Burst traffic

🔑 %80+ kullanım = kırmızı bölge. Sürpriz spike'ı tampon yok.


🚦 Auto-scaling — Reactive#

HPA (CPU + Memory)#

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: payments
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: payments
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target: {type: Utilization, averageUtilization: 70}
    - type: Resource
      resource:
        name: memory
        target: {type: Utilization, averageUtilization: 80}
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: Percent
          value: 100   # 2x scale up max 1 dk'da
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300   # 5 dk bekle
      policies:
        - type: Percent
          value: 25    # her seferinde max %25 scale down
          periodSeconds: 60

KEDA (event-driven)#

# Queue depth'e göre worker scale
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: queue-worker
spec:
  scaleTargetRef:
    name: worker
  minReplicaCount: 0
  maxReplicaCount: 50
  triggers:
    - type: aws-sqs-queue
      metadata:
        queueURL: <SQS_URL>
        queueLength: '10'   # 10+ message → scale up

Cluster Autoscaler / Karpenter#

  • HPA pod'ları çoğaltır
  • Karpenter node ekler (gerekirse)
  • Cost-aware: spot instance + right-size

🎯 Predictive Scaling#

Reactive scaling ≠ yeterli. Spike öncesi scale up gerekir.

Cron-based (predictable)#

# KEDA cron trigger
triggers:
  - type: cron
    metadata:
      timezone: Europe/Istanbul
      start: 0 9 * * *      # her sabah 09:00
      end: 0 18 * * *       # 18:00
      desiredReplicas: '20' # business hours daha fazla

Event-based (Black Friday)#

  • 1 hafta önce başla
  • Manuel scale up baseline
  • Load test ile doğrula
  • Post-event scale down

ML-based (deneysel)#

  • Geçmiş 6 ay datasından LSTM eğit
  • 30 dk önceden traffic tahmini
  • HPA buffer

🧪 Load Testing — Hipotezi Doğrulamak#

k6 (modern, JavaScript)#

// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '5m', target: 100 },   // ramp-up to 100 RPS
    { duration: '10m', target: 100 },  // steady
    { duration: '2m', target: 500 },   // spike
    { duration: '5m', target: 500 },   // sustained
    { duration: '5m', target: 0 },     // ramp-down
  ],
  thresholds: {
    http_req_duration: ['p(99)<2000'],   // p99 < 2s
    http_req_failed: ['rate<0.01'],       // <%1 fail
  },
};

export default function () {
  const res = http.get('https://api.<DOMAIN>/payments/123');
  check(res, { 'status 200': (r) => r.status === 200 });
  sleep(1);
}
k6 run load-test.js

Locust (Python)#

from locust import HttpUser, task, between

class APIUser(HttpUser):
    wait_time = between(1, 5)

    @task(3)
    def get_payment(self):
        self.client.get("/payments/123")

    @task(1)
    def post_payment(self):
        self.client.post("/payments", json={"amount": 100})

Test ortamı stratejisi#

  • Staging cluster = prod'un %30'u (ölçek)
  • Shadow traffic prod'da: gerçek user → mirror → test cluster
  • Production load test: blast radius düşük, off-peak (önerilmez ama bazı durumlarda)

📋 Capacity Review Cycle#

Quarterly review#

1. Mevcut kullanım dashboard'u (CPU/Mem/Disk/DB conn)
2. Son 90 gün trend
3. Yeni feature / customer growth forecast
4. Headroom değerlendirmesi
5. Black Friday / büyük event kontrol
6. Action items: scale up, optimize, archive

Annual review#

  • Hardware refresh planı
  • Cloud commitment (Reserved Instance, Savings Plans)
  • Multi-region kapasite
  • DR kapasitesi (tam yarısı standby)

🚫 Anti-Pattern Tablosu#

Anti-pattern Niye kötü Doğru
"Yeterli mi" sezgi Sürpriz outage Veri-bazlı forecast
%95+ kullanım kabul Spike'da çökme %30+ headroom
Auto-scaling yok Manuel rampaup, gece geç HPA + KEDA
Load test yok Real traffic'te öğrenilen Quarterly load test
Forecast linear-only Seasonality kayıp Holt-Winters / ML
Black Friday hazırlığı son hafta Gerçekçi değil 4-6 hafta önce
HPA sadece CPU Memory / queue ihmal Multi-metric
Scale down agresif Trafik geri spike'ında pod yok Stabilization window
Predictive scaling yok Reactive lag Cron + event-based
Capacity → SRE'in tek işi Dev'ler ölçeği bilmez Per-service capacity ownership
DR kapasitesi yarım Region down → çökme DR site = prod'un %50+

📋 Capacity Planning Checklist#

[ ] Anahtar metrikler dashboard'da (CPU/Mem/Disk/Conn/RPS)
[ ] Headroom alarmı (%80+ kullanım)
[ ] HPA min/max/target tanımlı tüm prod servis
[ ] KEDA queue / event-driven workload'lar için
[ ] Cluster Autoscaler / Karpenter
[ ] Quarterly load test (k6 / Locust)
[ ] Forecast: linear + seasonality
[ ] Black Friday / büyük event playbook (4-6 hafta önce)
[ ] Predictive scaling: cron veya ML
[ ] Cost-aware: spot + savings plan
[ ] DR kapasitesi (region failover sonrası %100)
[ ] Quarterly capacity review meeting
[ ] Annual: hardware refresh planı
[ ] Per-service ownership (dev'ler bilir)
[ ] Documentation: scale up runbook

📚 Referanslar#


"Capacity 'çok kaynak' değil — doğru kaynak doğru zamanda. Forecast olmadan scale, paranın israfı; load test olmadan büyüme, müşterinin israfı."