Ekim 2 2026

Ölçeklenen Altyapılarda Observability Maliyetini Yönetme: FinOps ve Sampling Stratejileri

Ay başında Datadog, New Relic veya AWS CloudWatch faturası geldiğinde dashboard’lardaki p99 gecikme grafiklerinden daha hızlı yükselen tek bir metrik vardır: Finans direktörünün nabzı. Modern bir DevOps mimarisinde mikroservislerin sayısı ve trafik hacmi arttıkça, observability altyapısının maliyeti çoğu zaman production ortamının compute maliyetini geride bırakır. Sistemin kör noktalarını kapatmak isterken bütçeyi tüketmek sürdürülebilir değil. Doğru bir FinOps yaklaşımı ve akıllı log yönetimi stratejileriyle, sistem görünürlüğünden ödün vermeden veri hacmini %60 ila %80 oranında düşürmek mümkün.

Fatura Neden Şişer? Görünmez Maliyet Kalemleri

Kıdemli mühendislerin sıkça düştüğü tuzak şudur: “Her şeyi loglayalım, OpenSearch veya Loki’ye basalım; lazım olursa grep’leriz.” Trafiğiniz saniyede 100 istek seviyesindeyken bu kabul edilebilir bir tembelliktir. Ancak saniyede 50.000 request aldığınız anda bu alışkanlık bir bütçe felaketine dönüşür.

Maliyeti patlatan üç ana faktör vardır:

  • Sağlık Kontrolleri (Health Checks): Kubernetes liveness/readiness probları ve ALB ping’leri log havuzunuzun %30’unu oluşturabilir. HTTP 200 GET /healthz satırının size hata anında hiçbir faydası yoktur.
  • Yüksek Kardinalite (High Cardinality): Metrik etiketlerine (label) user_id, order_id gibi sınırsız varyasyonu olan değerler eklemek, time-series veritabanınızın (Prometheus/Mimir) bellek tüketimini ve ingest maliyetini katlar.
  • Head-Based Sampling Hataları: Tracing verisinde rastgele %5 sampling aldığınızda, sistemdeki asıl yakalamak istediğiniz 500 hatalarının ve p99 outlier’larının da %95’ini çöpe atarsınız. Geriye sadece gürültü kalır.

Log Yönetimi: Vector ile Edge Düzeyinde Filtreleme ve Dönüştürme

Logları merkezi sisteme göndermeden önce daemonset katmanında filtrelemek en ucuz ve en etkili çözümdür. Logstash veya Fluentd gibi JVM/Ruby tabanlı hantal çözümler yerine Rust ile yazılmış düşük ayak izli Vector bu iş için biçilmiş kaftandır.

Aşağıdaki Vector konfigürasyonunda üç kritik optimizasyon yapıyoruz: Başarılı health check’leri drop ediyoruz, hassas verileri tokenize ediyoruz ve kalan debug loglarını örnekliyoruz (sampling).

cat << 'EOF' > /etc/vector/vector.yaml
sources:
  kubernetes_logs:
    type: kubernetes_logs

transforms:
  filter_health_checks:
    type: filter
    inputs:
      - kubernetes_logs
    # HTTP 200 dönen healthz loglarını doğrudan çöpe at
    condition: '!includes(["/healthz", "/readyz", "/livez"], .message)'

  drop_noisy_debugs:
    type: filter
    inputs:
      - filter_health_checks
    # Log seviyesi DEBUG olanları %90 oranında sample et
    condition: |
      if .level == "debug" {
        random() < 0.1
      } else {
        true
      }

  sanitize_and_prune:
    type: remap
    inputs:
      - drop_noisy_debugs
    source: |
      # Gereksiz Kubernetes metadata alanlarını temizle
      del(.kubernetes.pod_labels)
      del(.kubernetes.pod_annotations)
      
      # Kredi kartı gibi hassas verileri maskele
      .message = replace(.message, r'[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}', "[REDACTED_CC]")

sinks:
  elasticsearch_out:
    type: elasticsearch
    inputs:
      - sanitize_and_prune
    endpoints:
      - "https://elasticsearch.internal:9200"
    mode: "bulk"
EOF

Neden böyle yaptık? Kubernetes metadata’sındaki pod annotation’ları production’da devasa JSON payload’ları üretir. Bunları edge katmanında del() fonksiyonu ile silmek, taşınan ve indekslenen veri boyutunu anında %25 azaltır.

Tracing Verisinde Tail-Based Sampling Stratejisi

Geleneksel distributed tracing araçları trace’in başlangıcında karar verir (Head-based sampling). Bir istek geldiğinde yazı tura atılır: %1 seçilirse tüm akış kaydedilir. Fakat istek sırasında bir mikroservis patlarsa ve siz o isteği sample etmediyseniz, elinizde hiçbir şey kalmaz.

Tail-based sampling, isteğin tamamlanmasını bekler. İstek hata aldıysa veya belirlenen latency eşiğini aştıysa trace’i %100 saklar; sorunsuz HTTP 200 yanıtlarını ise agresif bir şekilde eler.

Bunu OpenTelemetry (OTel) Collector katmanında şu şekilde konfigüre ediyoruz:

cat << 'EOF' > /etc/otelcol/config.yaml
receivers:
  otlp:
    protocols:
      grpc:
      http:

processors:
  tail_sampling:
    decision_wait: 10s
    num_traces: 10000
    expected_new_traces_per_sec: 2000
    policies:
      # 1. Kural: Status code ERROR olan tüm trace'leri eksiksiz tut
      - name: drop_errors_policy
        type: status_code
        status_code: { status_codes: [ ERROR ] }

      # 2. Kural: Süresi 1.5 saniyeyi aşan tüm yavaş istekleri yakala
      - name: latency_policy
        type: latency
        latency: { threshold_ms: 1500 }

      # 3. Kural: Kalan normal akıştan sadece %1 örnek al
      - name: probabilistic_policy
        type: probabilistic
        probabilistic: { sampling_percentage: 1.0 }

exporters:
  otlp/backend:
    endpoint: "tempo.monitoring.svc.cluster.local:4317"
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [tail_sampling]
      exporters: [otlp/backend]
EOF

Bu konfigürasyonda OTel Collector, trace parçalarını decision_wait: 10s süresince bellekte tutar. Span ağacı tamamlandığında kuralları yukarıdan aşağıya değerlendirir. İstisna veya lag varsa diskte saklanır; yoksa veri hacmi anında %99 bastırılır.

Metriklerin Sessiz Katili: Kardinaliteyi Düşürme (Metric Relabeling)

Datadog veya Prometheus faturalarında metrik maliyetlerinin patlamasının temel nedeni “Custom Metrics” ve time-series patlamalarıdır. Bir metriğin kaç time-series ürettiğini şu formülle hesaplarız:

Total Time Series = (Değer_Sayısı_Label_A) * (Değer_Sayısı_Label_B) * (Değer_Sayısı_Label_C)

Eğer bir yazılımcı HTTP istek metriğine user_id veya rastgele UUID’ler içeren path eklediyse, o metrik saniyeler içinde 500.000 time-series üreterek bellek limitlerini vurur. Prometheus scrape konfigürasyonunda metric_relabel_configs kullanarak bu etiketleri ingest anında silmelisiniz:

scrape_configs:
  - job_name: 'api-gateway'
    kubernetes_sd_configs:
      - role: pod
    metric_relabel_configs:
      # Belirli yüksek kardinaliteli dinamik labelları drop et
      - action: labeldrop
        regex: '(user_id|client_ip|session_token)'
      
      # REST URL path'lerindeki UUID'leri regex ile normalize et
      - source_labels: [__name__, path]
        regex: 'http_requests_total;/api/v1/orders/[a-f0-9\-]+'
        target_label: path
        replacement: '/api/v1/orders/:id'

Yukarıdaki işlem yapılmadığında /api/v1/orders/a1b2-c3d4 ve /api/v1/orders/e5f6-g7h8 iki ayrı metrik olarak depolanır. Regex normalizasyonu sayesinde her iki istek de /api/v1/orders/:id altında birleşir; metrik tekilleşir ve time-series sayısı tek hanelere iner.

Veri Yaşam Döngüsü: Tiering ve Soğuk Depolama

SRE ekiplerinin yaptığı analizler, log sorgularının %92’sinin son 48 saat içinde yazılan verilere yapıldığını gösteriyor. 30 gün önceki bir INFO logunu pahalı NVMe disklerde tutmak safi kaynak israfıdır.

Loki veya Elasticsearch kullanırken iki katmanlı (hot/cold) saklama stratejisi kurgulayın:

  • Hot Tier (0-7 Gün): Hızlı sorgulama için NVMe diskler veya SSD blok depolama. Tam indeksleme açık.
  • Warm/Cold Tier (7-30 Gün): İndeksleri küçültülmüş, read-only modda çalışan uygun maliyetli HDD veya S3/GCS object storage katmanı.
  • Deep Archive (30+ Gün): Yalnızca regülasyon (KVKK/GDPR/PCI-DSS) gereği tutulması gereken veriler için S3 Glacier / GCS Archive lifecycle kuralları. İndeks yok, yalnızca ham gzip blokları.

Özet: FinOps Mühendisliği Bir Süreçtir

Observability sistemlerini optimize etmek, kör uçuş yapmak anlamına gelmez. Tam aksine, doğru sinyali yakalayıp gürültüyü (noise) elimine etmektir. Edge katmanında Vector ile gürültüyü kesin, APM tarafında tail-based sampling ile hatalara odaklanın ve scraping aşamasında kardinaliteyi regex ile dizginleyin. Bu üç adımı attığınızda, faturanız düşerken platformunuzun asıl sorunları tespit etme kabiliyeti katlanarak artacaktır.

Category: Genel | LEAVE A COMMENT
Ağustos 22 2026

FinOps 2.0: AWS/Cloud Faturasını Otomatik Kısıtlayan Event-Driven Mimariler

Her ayın sonunda gelen o meşhur kabarık faturayı görüp Slack kanallarında “Bu p3.8xlarge instance’ı kim açık unuttu?” cadı avı başlatmaktan yorulduysanız, yalnız değilsiniz. Geleneksel bütçe uyarıları reaktiftir; fatura eşiği aşıldığında iş işten çoktan geçmiş olur. Modern FinOps yaklaşımı, cloud maliyet yönetimini sadece raporlama tablosu olmaktan çıkarıp, AWS altyapısında gerçek zamanlı çalışan bir otomasyon zincirine dönüştürmeyi gerektiriyor.

Bu yazıda; gecikmeli Cost and Usage Report (CUR) analizlerini bir kenara bırakıp, EventBridge, CloudWatch Metric Streams ve Lambda tabanlı event-driven bir maliyet kısıtlama (circuit breaker) mimarisini nasıl kuracağımızı adım adım ele alıyoruz.

Geleneksel Bütçe Uyarıları Neden İşe Yaramaz?

AWS Budgets veya CloudWatch Billing Alarms kurduğunuzda, arka planda çalışan telemetri verisi gerçek zamanlı değildir. CloudWatch billing metrikleri genellikle 8 ila 14 saatlik bir gecikmeyle (delay) güncellenir. Bir developer cuma akşamı yanlışlıkla 10 nodeluk bir GPU kümesini ayağa kaldırıp unuttuysa, pazartesi sabahı gelen e-posta sadece felaketin faturasını tebliğ eder.

Bize gereken şey: Anomaly Detection + Immediate Event Routing + Automated Remediation. Yani faturanın toplamını değil, kaynak oluşturma hızını (velocity), beklenmeyen metrik sıçramalarını ve yetim (orphaned) kaynakları anlık yakalayan bir mimari.

Event-Driven FinOps Mimarisi Nasıl Çalışır?

Kurgulayacağımız mimari üç ana ayaktan oluşuyor:

  1. Sinyal Katmanı: AWS Cost Anomaly Detection, AWS Health Events, CloudTrail Management Events ve Config Rule ihlalleri.
  2. Yönlendirme Katmanı (Routing): Amazon EventBridge default bus veya custom bus. Gelen payload’u filtreleyip uygun remediation hedefine yönlendirir.
  3. Aksiyon Katmanı (Execution): AWS Lambda veya Step Functions. Kaynağı durdurur, scale-in yapar, volume snapshot’ı alıp diski siler ya da doğrudan security group seviyesinde trafiği keser.

Adım 1: Cost Anomaly Detection için EventBridge Kuralı

AWS Cost Anomaly Detection, makine öğrenmesi modelleriyle harcama paternlerinizi analiz eder. Bir anomali tespit edildiğinde doğrudan EventBridge’e event fırlatabilir. Aşağıdaki CloudFormation / EventBridge Pattern tanımı, belirlenen eşik üzerindeki anomalileri dinler:

{
  "source": ["aws.cost-anomaly-detection"],
  "detail-type": ["Cost Anomaly Detected"],
  "detail": {
    "anomalyScore": [{ "numeric": [">=", 80] }],
    "impact": {
      "totalImpactPercentage": [{ "numeric": [">=", 50] }]
    }
  }
}

Bu pattern; anomali skoru 80’in üzerinde olan ve harcama etkisinin beklenen baseline’a göre en az %50 saptığı senaryoları yakalar. Anlamsız mikro dalgalanmalar için Lambda tetiklenmez.

Adım 2: Dev/Staging Ortamlarında Kaçak Kaynakları Kesen Lambda

Birçok şirkette faturayı patlatan şey prod ortamı değil, dev/stage hesaplarında “test edip sileceğim” denilerek unutulan yüksek profilli kaynaklardır. Aşağıdaki Python tabanlı Lambda fonksiyonu, tag eksikliği olan veya anomali üreten instance’ları hedef alarak devreye girer. Dry-run kontrolü ve güvenli tag filtresi içerir:

import boto3
import os
import json
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

ec2 = boto3.client('ec2')
TAG_IMMUNITY_KEY = "FinOpsImmunity"
ALLOWED_ENVIRONMENTS = ["development", "staging", "sandbox"]

def lambda_handler(event, context):
    logger.info(f"Received event: {json.dumps(event)}")
    
    # Hedef filtreleri: Sadece dev/stage hesaplar ve belirli instance tipleri
    filters = [
        {'Name': 'instance-state-name', 'Values': ['running']},
        {'Name': 'tag:Environment', 'Values': ALLOWED_ENVIRONMENTS}
    ]
    
    response = ec2.describe_instances(Filters=filters)
    instances_to_stop = []

    for reservation in response['Reservations']:
        for instance in reservation['Instances']:
            instance_id = instance['InstanceId']
            instance_type = instance['InstanceType']
            tags = {t['Key']: t['Value'] for t in instance.get('Tags', [])}
            
            # Bağışıklık tag'i var mı?
            if tags.get(TAG_IMMUNITY_KEY, "false").lower() == "true":
                logger.info(f"Instance {instance_id} has immunity tag. Skipping.")
                continue
                
            # Büyük/Pahalı aileleri hedef al (GPU, High Memory vb.)
            if instance_type.startswith(('p3', 'p4', 'g4', 'g5', 'r5b', 'x2gd')):
                logger.warning(f"High cost instance detected without immunity: {instance_id} ({instance_type})")
                instances_to_stop.append(instance_id)

    if instances_to_stop:
        logger.info(f"Stopping instances: {instances_to_stop}")
        ec2.stop_instances(InstanceIds=instances_to_stop)
        return {"status": "SUCCESS", "stopped_instances": instances_to_stop}

    return {"status": "NO_ACTION", "stopped_instances": []}

Burada kritik olan felsefe şudur: Fail-safe by default. Prod hesabına dokunmamak için ortam etiketlerini katı şekilde izole ediyoruz ve geliştiricilere acil durumlarda kullanmaları için FinOpsImmunity=true gibi bir bypass tag mekanizması tanıyoruz.

Adım 3: Yetim (Orphaned) EBS ve Unassociated EIP Temizliği

Terraform ile altyapıyı yıkan ama lifecycle { prevent_destroy = true } veya unattached volume’leri unutan mühendislerin faturaya hediyesidir yetim kaynaklar. CloudWatch Event yerine her gece EventBridge Schedule (Cron) ile tetiklenen hafif bir garbage collector kuralı tanımlayalım:

# AWS CLI ile Unattached (Available) EBS Volume'leri sorgulama
aws ec2 describe-volumes \
    --filters Name=status,Values=available \
    --query "Volumes[*].{ID:VolumeId,Size:Size,Created:CreateTime}" \
    --output table

Bunu otomatize ederken dikkat: Silmeden önce mutlaka snapshot alın. Event-driven mimarilerde en büyük risk, veri kaybına yol açabilecek agresif otomasyonlardır. Lambda’nın adımları şöyle olmalıdır:

  1. Volume state available mı?
  2. Tag’lerinde SnapshotBeforeDelete=true oluştur.
  3. Snapshot tetikle, snapshot tamamlandığında EventBridge’den gelen EC2 Snapshot Successful eventiyle eski volume’ü drop et.

Kubernetes / Karpenter için Runaway Cost Breaker

Eğer EKS üzerinde Karpenter veya Cluster Autoscaler kullanıyorsanız, container’ların crashloop’a girip sürekli yeni node istemesi sonucu dakikalar içinde onlarca nodeluk bir cluster anomalisi yaşayabilirsiniz.

Karpenter’ın NodePool limitleri bu işin ilk savunma hattıdır ama tek başına yetmez. Event-driven bir Lambda ile Karpenter NodePool CRD’sinin limitlerini dinamik olarak sıkılaştırabilirsiniz:

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: default
spec:
  limits:
    cpu: "100"
    memory: 400Gi
  template:
    spec:
      requirements:
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["spot"]
        - key: "karpenter.k8s.aws/instance-category"
          operator: In
          values: ["c", "m", "r"]

Limit aşıldığında cluster’a yeni node eklenmesi engellenir. Bu aşamada Prometheus Alertmanager’dan EventBridge Webhook’una düşen bir alarm ile nöbetçi SRE’ye Slack üzerinden interactive button ile onay düşürmek en sağlıklı yaklaşımdır.

Least Privilege IAM İzni

FinOps otomasyon Lambda’nızın AdministratorAccess almasına gerek yoktur. Sadece durdurma ve tanımlama yetkilerini içeren sıkı bir IAM policy tanımlayın:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "FinOpsEC2Operations",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeVolumes",
                "ec2:StopInstances",
                "ec2:CreateSnapshot",
                "ec2:DeleteVolume"
            ],
            "Resource": "*"
        }
    ]
}

Özet: FinOps Kültür Değil, Kod Tabanıdır

Mühendisleri spreadsheet tablolarına bakarak eğitmek bir yere kadar çalışır. İnsan hata yapar, acil durumlarda makineler açık unutulur. FinOps 2.0; kuralları şirket wikisine yazmak yerine EventBridge kurallarına, Lambda fonksiyonlarına ve Kubernetes admission controller’larına yazmaktır.

Reaktif fatura şoklarından proaktif event-driven kısıtlamalara geçtiğinizde, hem CFO’nuz daha rahat uyur hem de nöbetçi SRE hafta sonu faturayı değil asıl işi olan sistem güvenilirliğini düşünür.

Category: Genel | LEAVE A COMMENT