kertenkerem_
· DevOps · 5 dk okuma

SLO/SLI/SLA: DevOps Ekiplerine Güvenilirlik Mühendisliği Rehberi

Gecenin 3’ünde, sırf bir API gateway endpoint’i anlık olarak 500ms yavaş yanıt verdi diye PagerDuty alarmıyla uyanıp monitöre boş gözlerle baktıysanız, tebrikler: Yanlış kurgulanmış bir alarm stratejisinin kurbanı oldunuz. Modern mikroservis mimarilerinde sistemlerin kararlılığını ve güvenilirlik (reliability) seviyesini ölçmek, her saniye CPU veya memory değerlerini izleyip eşik aşılınca ortalığı ayağa kaldırmakla olmaz. SRE (Site Reliability Engineering) pratiğinde sistem sağlığını ve mühendislik eforunu yönetmek için üç kısaltma kullanırız: SLI, SLO ve SLA. Bu yazıda tanımların ötesine geçip production ortamında işinize yarayacak error budget hesaplarını ve Prometheus üzerinde burn rate tabanlı dinamik alarmların nasıl kurulacağını göreceğiz.

Kavram karmaşasını çözelim: SLI, SLO ve SLA

Bu üç kavram sık sık birbirine karıştırılır ya da aynı şeymiş gibi kullanılır. Aralarındaki ilişkiye bakalım:

  • SLI (Service Level Indicator): “Sistemimiz şu an ne kadar iyi çalışıyor?” sorusunun cevabıdır. Doğrudan ölçülebilir, anlık teknik metriklerdir. Örneğin “Son 5 dakikadaki başarılı HTTP isteklerinin (2xx/3xx/4xx), toplam isteklere oranı.”
  • SLO (Service Level Objective): “Sistemin ne kadar iyi çalışmasını hedefliyoruz?” sorusunun yanıtıdır. SLI metriğine bağlı bir hedef ve zaman aralığı tanımlar. Örneğin “Gelen tüm isteklerin %99.9’u, 30 günlük kayan pencerede (rolling window) 200ms’in altında yanıt vermelidir.”
  • SLA (Service Level Agreement): “Sistemi hedeflediğimiz kadar ayakta tutamazsak ne kadar ceza ödeyeceğiz?” sorusunun ticari ve hukuki cevabıdır. Mühendislerden çok hukuku, ürün yönetimini (Product Management) ve müşterileri ilgilendirir. Genellikle SLO değerinden daha düşük bir taahhüt içerir (örneğin SLO %99.9 ise SLA %99.5 olabilir).

Kısacası SLI ölçer, SLO hedefler, SLA ise patlarsa fatura keser.

Hata bütçesi (error budget): neden kusursuzluk aramıyoruz?

SRE felsefesinin en temel kabullerinden biri şu: %100 güvenilirlik (reliability) yanlış bir hedeftir. Kullanıcılarınızın internet bağlantısı bile %100 kesintisiz değilken altyapınız için %100 uptime hedeflemek yalnızca bütçenizi tüketir ve ekibin hızını (velocity) sıfırlar.

Bunun yerine error budget kavramını kullanırız. Formül basit:

Error Budget = 100% - SLO%

30 günlük SLO hedefimizi %99.9 olarak belirlediysek, 30 günde %0.1 oranında hata yapma veya kesinti yaşama hakkımız var demektir. 30 gün 2.592.000 saniyedir. Hata bütçemiz tam olarak 2.592 saniye, yani yaklaşık 43.2 dakikadır.

Bu bütçe yalnızca sistem çöktüğünde tükenmez. Yeni deployment’lar sırasındaki yavaşlıklar ve geçici veritabanı bağlantı kayıpları da bu bütçeden yer. Ay sonuna doğru hata bütçeniz duruyorsa production ortamına korkusuzca riskli güncellemeler (feature deployment) gönderebilirsiniz. Bütçe tükendiyse yeni deployment’ları durdurur, yalnızca reliability/bug-fix işlerine odaklanırsınız.

Prometheus ile SLI tanımlama (pratik uygulama)

Biraz pratiğe geçelim. Elimizde Prometheus tarafından scrape edilen bir HTTP servisinin metrikleri olduğunu varsayalım. En popüler SLI türlerinden biri olan availability (kullanılabilirlik) metriğini hesaplayalım.

Burada kritik bir SRE detayı var: Genellikle 5xx durum kodlarını sunucu hatası (unavailability) sayarız. 4xx kodlarını (örneğin 404 veya 401) kullanıcı hatası kabul eder, sistemin sağlığını bozmadıkları için SLI hesabına katmayız (tabii 4xx’ler aniden tavan yapmadıysa).

Yazacağımız PromQL sorgusu şöyle:

sum(rate(http_requests_total{job="my-service", status!~"5.."}[5m]))
/
sum(rate(http_requests_total{job="my-service"}[5m]))

Bu sorgu son 5 dakika içinde 5xx dışındaki isteklerin toplam isteklere oranını verir. Çıktı 0 ile 1 arasında olur (örneğin 0.9995, yani %99.95 başarı).

Burn rate alerts: CPU alarmlarını çöpe atın

Geleneksel alert mekanizmaları genellikle “Anlık CPU %90’ı geçerse Slack’e mesaj at” ya da “Hata oranı %1’i geçerse nöbetçiyi ara” biçimindedir. Bu yaklaşım iki büyük sorun yaratır:

  1. Gürültü (alert fatigue): Anlık bir trafik spike’ı yüzünden hata oranı 1 dakikalığına %2’ye çıkıp kendi kendine düzelebilir. Uykunuz boşuna bölünür.
  2. Yavaş ölümler (slow burns): Hata oranınız saatlerce %0.2’de kalabilir. Bu oran geleneksel alarmları tetiklemez ama 30 günlük %99.9’luk SLO bütçenizi sinsice sıfırlar.

SRE pratiği bu sorunu burn rate (tüketim hızı) alarmlarıyla çözer. Burn rate, hata bütçenizi ne kadar hızlı tükettiğinizi gösteren katsayıdır.

  • Burn Rate = 1: Bütçeniz tam olarak planlanan sürede (örneğin 30 günde) tükenecek demektir.
  • Burn Rate = 14.4: Bütçenizin %2’sini yalnızca 1 saat içinde tüketeceğiniz anlamına gelir. Acil müdahale (Pager) gerekir.
  • Burn Rate = 6: Bütçenizin %5’ini 6 saatte tüketeceksiniz demektir. Bu durumda bilet (Jira ticket) açmak yeterlidir.

Prometheus kural dosyası (Prometheus alert rules)

Aşağıdaki konfigürasyon bloğu, Google SRE Workbook standartlarına uygun yazılmış, çoklu zaman pencereli (multi-window, multi-burn-rate) bir alert kuralı örneği. Anlık gürültüleri engeller, yavaş bütçe tüketimini de kaçırmaz.

groups:
  - name: service-slo-alerts
    rules:
      # Critical Alert: 1 saatlik burn rate > 14.4 VE son 5 dakikada da bu eğilim devam ediyorsa
      - alert: ServiceAvailabilityCriticalBurnRate
        expr: |
          (
            sum(rate(http_requests_total{status=~"5.."}[1h]))
            /
            sum(rate(http_requests_total[1h]))
          ) > (1 - 0.999) * 14.4
          and
          (
            sum(rate(http_requests_total{status=~"5.."}[5m]))
            /
            sum(rate(http_requests_total[5m]))
          ) > (1 - 0.999) * 14.4
        for: 2m
        labels:
          severity: critical
          tier: platform
        annotations:
          summary: "Hızlı Hata Bütçesi Tüketimi (Burn Rate 14.4x)"
          description: "Hata bütçesi son 1 saatte çok hızlı tükeniyor! Current error rate: {{ $value | humanizePercentage }}"

      # Warning Alert: 6 saatlik burn rate > 6 (Bütçenin %5'i 6 saatte bitiyor)
      - alert: ServiceAvailabilityWarningBurnRate
        expr: |
          (
            sum(rate(http_requests_total{status=~"5.."}[6h]))
            /
            sum(rate(http_requests_total[6h]))
          ) > (1 - 0.999) * 6
          and
          (
            sum(rate(http_requests_total{status=~"5.."}[30m]))
            /
            sum(rate(http_requests_total[30m]))
          ) > (1 - 0.999) * 6
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "Yavaş Hata Bütçesi Tüketimi (Burn Rate 6x)"
          description: "Son 6 saattir hata bütçesi eriyor. Nöbetçi ekibin mesai saatlerinde incelemesi önerilir."

Kurallarda (1 - 0.999) * 14.4 gibi dinamik bir formül kullandığımıza dikkat edin. Buradaki 0.999 SLO hedefimiz olan %99.9’dur. Yarın bu hedefi %99.5’e çekmek isterseniz yalnızca bu katsayıları değiştirmeniz yeterli olur.

Bu yapıyı kurduktan sonra sizi ne bekliyor?

Bu sisteme geçmek teknik bir araç değişiminden fazlası, ciddi bir kültürel dönüşümdür. Burn rate alarmlarına geçtiğinizde:

  • Gecenin yarısında uyanma oranınız (false-positive paging) dramatik şekilde düşecek.
  • Ekipler “Bu hafta çok downtime oldu, deployment yapmayalım” kararını hissiyatla değil, doğrudan Grafana paneline (Error Budget Dashboard) bakarak somut verilerle verecek.
  • Yazılım geliştiriciler ve sistem yöneticileri aynı dili konuşmaya başlayacak: “Hata bütçemiz ne kadar kaldı?”

Bu dönüşümü kendi sistemlerinizde başlatmak için en kritik 3 servisinizi belirleyin, her biri için basit bir kullanılabilirlik SLI’ı yazın ve error budget grafiğinizi oluşturun. Mükemmel sistem kesintisiz çalışan sistem değildir. Mükemmel sistem, ne zaman ve ne kadar hata yapabileceğini bilen ve bunu kontrol altında tutan sistemdir.