Sertaç Yıldırım saha notları

Ana sayfa → Teknik

SLO ve Hata Bütçesi: Hedef Değil, Pazarlık Aracı

Temmuz başı, çeyrek planlaması. Ürün yöneticisi: “Bu çeyrek dört özellik.” Ben: “Emir servisi kararsız, iki sprint güvenilirliğe vermemiz lazım.” 50 dakika tartıştık, kimse ikna olmadı. İkimizin de elinde sayı yoktu; sadece his vardı ve benim hissim onunkinden daha değerli değildi.

Özet
  • SLO bir hedef değil, bir anlaşmadır. Ürün ve mühendislik “ne kadar kötü olmaya razıyız” sorusuna önceden, birlikte cevap verir.
  • SLI, kullanıcının gördüğü şeydir. Sunucunun ayakta olması değil, emrin 1 saniye içinde kabul edilmesi. Bizde uptime %99,98 iken müşteri şikâyet ediyordu.
  • %99,9 ayda 43 dakika demek. Rakamı hesaplamadan hedef koyma; %99,99 ayda 4,3 dakika ve haftalık deploy trenimiz bunu tek başına yiyordu.
  • Bütçenin anlamı, bitince ne olacağıdır. Politikası yazılmamış SLO dashboard süsüdür. Bizde bütçe biterse o serviste özellik çıkışı durur.
  • Alarm eşiğe değil, yanma hızına kurulur. Burn rate alarmı, sabit %5 eşiğinin hiç görmediği saatlerce süren küçük sızıntıyı yakaladı.

Sahadan: 50 dakikalık tartışma, tek sayı

O toplantıdan sonra yaptığım ilk şey, son üç ayın yük dengeleyici (load balancer) loglarını açmak oldu. Soru basitti: emir gönderme isteklerinin kaçı başarılı ve zamanında döndü? Cevap, dashboard’ımızın söylediğinden çok farklıydı.

Dashboard uptime gösteriyordu: %99,98. Health check her 10 saniyede bir “ayaktayım” diyordu ve doğru söylüyordu. Ama emir istekleri başka bir hikâye anlatıyordu: Haziran’da 6,1 milyon emir isteğinin 14.200’ü ya hata aldı ya da 1 saniyeyi geçti. Başarı oranı %99,77. Ben yanlış şeyi ölçüyordum; sunucunun yaşadığını ölçüyordum, müşterinin emrinin geçip geçmediğini değil.

İkinci sürpriz, o 14.200 kötü isteğin nereden geldiğiydi. Tahminim “veritabanı”ydı. Değildi:

Kaynak (Haziran)Kötü istekPay
Dört haftalık deploy (her biri ~2.150)8.600%61
Tek bir veritabanı failover’ı3.900%27
Geri kalan her şey1.700%12
Toplam14.200%100

Monolit her deploy’da pod’ları sırayla kapatıyordu ama kapanan pod, üzerindeki istekleri bitirmeden ölüyordu. Haftada bir, piyasa açıkken, birkaç yüz müşterinin emri yarıda kalıyordu. Kimse fark etmemişti çünkü her biri birkaç saniyelik bir sıçramaydı ve hiçbir alarm onu yakalayacak kadar uzun sürmüyordu.

İkinci toplantıya bu tabloyla girdim. Tartışma 10 dakika sürdü. Ürün yöneticisi tabloya bakıp tek bir şey sordu: “Deploy’u düzeltirsek bu sayı ne kadar düşer?” Artık aynı soruyu soruyorduk.

Sayı yoksa tartışma, kimin daha yüksek sesle konuştuğuna döner. Hata bütçesi, sesi masadan kaldırır.

SLI: kullanıcının gördüğü şey

SLI (service level indicator) ölçtüğün şeydir; SLO (service level objective) o ölçü için koyduğun hedeftir. Sıra önemli: yanlış SLI’a konan doğru hedef, sana sadece doğru bir sayıyla yanlış bir güven verir.

İyi SLI’ın üç özelliği var. Kullanıcının hissettiği şeyi ölçer. Oran olarak yazılır: iyi olay / toplam olay. Ve kullanıcıya en yakın yerden ölçülür. Bizim emir servisi için son hâli şu:

  • İyi olay: emir isteği 1 saniye içinde başarılı cevap döndü.
  • Toplam: bütün emir istekleri; kullanıcı hatası olan 4xx’ler hariç. Yetersiz bakiye yüzünden reddedilen emir, servisin hatası değil; doğru çalışmasının kanıtı.
  • Ölçüm yeri: yük dengeleyici. Uygulama kendi logunda ölmüş pod’un isteğini göremez; yük dengeleyici görür.

Her şeye SLO koymadık. Emir gönderme ve para çekme talebi için %99,9, hesap ekstresi ve raporlar için %99,5. Ekstre üç dakika geç açılırsa müşteri söylenir; emir üç saniye geç giderse fiyat değişmiş olur. İkisine aynı hedefi koymak, ikisinin de önemini kaybettirir.

Hesap: %99,9 ayda kaç dakika?

Ürün yöneticisinin ilk önerisi %99,99 idi. Kulağa güven veriyor. Hesabını yapınca masadaki herkes aynı anda sustu:

Hata butcesi hesabi (emir-api, 30 gunluk pencere)
# SLO: son 30 gunde emirlerin %99.9'u 1 sn icinde basarili
hedef        = 0.999
pencere_dk   = 30 * 24 * 60             # 43.200 dakika
butce_dk     = pencere_dk * (1 - hedef) # 43.2 dakika tam kesinti

# Istek bazli ayni hesap (bizde gercek olcu bu)
aylik_istek  = 6_100_000
butce_istek  = aylik_istek * (1 - hedef) # 6.100 kotu istek

# Haziran gercegi
kotu_istek   = 14_200
tuketim      = kotu_istek / butce_istek  # 2.33 --> butcenin %233'u

# %99.99 olsaydi
butce_istek  = 610                       # tek bir kotu deploy ~2.150

Son satır tartışmayı bitirdi. Haftada bir deploy yapan bir monolit, tek bir deploy’da 2.150 kötü istek üretiyorsa, 610’luk bütçe ayın ilk Salısında biter. %99,99 bir hedef değil, bir dilekti. Tablo farkı gösteriyor:

SLO30 günde izin verilen kesinti6,1 milyon istekte kötü istek
%997 saat 12 dk61.000
%99,53 saat 36 dk30.500
%99,943,2 dk6.100
%99,9521,6 dk3.050
%99,994,3 dk610

%99,9’da anlaştık, ama bir şartla: Haziran’daki gerçek %99,77 idi. Yani hedefi koyduğumuz gün bütçenin iki katından fazlasını harcıyorduk. Bunu saklamadık; ilk iki sprintin neden güvenilirliğe gittiğinin cevabı tam olarak buydu. O iki sprintte tek bir işe odaklandık: kapanan pod önce yeni istek almayı bırakıyor, elindeki istekleri bitiriyor, sonra ölüyor. Deploy başına kötü istek 2.150’den ~200’e indi. Hedef mevcut durumdan biraz iyi olmalı, ulaşılmaz değil. Ulaşılmaz hedef ilk hafta yok sayılmaya başlar.

Bütçe bitince ne olur?

SLO’nun asıl gücü hedefte değil, bütçe bittiğinde ne olacağının önceden yazılmasında. Politikası olmayan SLO, kimsenin bakmadığı bir grafiktir. Bizimki bir sayfa ve ürün yöneticisiyle ben imzaladık:

Bütçe varken
  • Özellik çıkışı normal akışta
  • Deney ve riskli değişiklik serbest
  • Bütçenin %10’u bile harcanmıyorsa: fazla temkinlisin, daha sık çık
  • %50’yi geçince: sıradaki deploy ikinci bir gözden geçirmeyle
Bütçe bitince (%100)
  • O serviste yeni özellik çıkışı durur
  • Çıkan tek şey: güvenilirlik işi, güvenlik düzeltmesi, düzenleyici zorunluluk
  • Freeze sadece o servis için, bütün şirket için değil
  • Bitiş: kök neden düzeltmesi canlıda ve son 7 günün burn rate’i 1’in altında

Politika Eylül’de sınandı. 9 Eylül’de hatalı bir sürüm 40 dakikada bütçenin %70’ini yaktı. Pencere zaten %38’deydi; aynı gün %108 oldu. Ertesi sabah freeze başladı. Kök neden düzeltmesi 12 Eylül’de çıktı, son 7 günün burn rate’i 17 Eylül’de 1’in altına indi; freeze yedi gün sürdü (10–17 Eylül). İki özellik bir sonraki sprinte kaydı.

Beklediğim tartışma hiç olmadı. Ürün yöneticisi o sabah ekip kanalına tek satır yazdı: “Kural bizim kuralımız.” Temmuz’da, sakin bir günde, kimse yangının içinde değilken yazılmış bir kural, Eylül’de yangının ortasında pazarlığa açılmadı. Bunun sebebi kuralın iyi olması değil, önceden yazılmış olmasıydı.

Hata bütçesi, “ne kadar kötü olmaya razıyız” sorusunun sakin bir günde verilmiş cevabıdır.

Burn rate: eşik değil, hız

SLO’yu koyduktan sonra eski alarmlarımıza baktık: “hata oranı 10 dakika boyunca %5’in üstündeyse çal.” Bu eşik iki şeyi yanlış yapıyor. 3 dakikalık bir sıçramada gereksiz yere susar ya da çalar; bütün gün süren küçük bir bozulmayı ise hiç görmez. Oysa bütçeyi bitiren şey çoğu zaman o küçük bozulmadır.

Burn rate (yanma hızı), bütçenin normalden kaç kat hızlı harcandığıdır. 1 ise bütçe tam 30 günde biter. 14,4 ise iki günde. Alarmı bu hıza kurduk:

Iki pencereli burn rate alarmi
# burn_rate = hata_orani / (1 - hedef)
# hedef %99.9 --> hata orani %1.44 ise burn rate 14.4

# HIZLI YANMA: nobetciyi uyandir (gece de)
#   1 saatte butcenin %2'si gider
uzun_pencere = 1 saat,  kisa_pencere = 5 dk,  burn_rate > 14.4

# YAVAS YANMA: ekip kanali (sabah bakilir)
#   6 saatte butcenin %5'i gider
uzun_pencere = 6 saat,  kisa_pencere = 30 dk, burn_rate > 6

# Iki pencere birden sart: uzun pencere "gercekten oluyor mu",
# kisa pencere "hala oluyor mu" sorusunu cevaplar.
# Sorun bitince kisa pencere hemen susar, alarm saatlerce calmaz.

Ekim’de bunun işe yaradığını gördük. VİOP emirlerinin bir alt türündeki konfigürasyon hatası yüzünden toplam emir trafiğinin %0,6’sı hata alıyordu. Eski %5 eşiği bunu hiçbir zaman görmezdi. Yavaş yanma alarmı 6. saatte ekip kanalına düştü, ertesi sabah düzeltildi. Toplam maliyet bütçenin yaklaşık %9’u oldu. Alarm olmasaydı fark ettiğimiz yer büyük ihtimalle müşteri destek kuyruğu olacaktı.

Burn rate alarmını şimdilik sadece emir servisine kurduk; diğer servisler hâlâ sabit eşikte. Her servise aynı anda kurmak cazip ama yanlış SLI’a kurulan burn rate alarmı, yanlış şeyi daha hızlı haber verir. Önce SLI, sonra alarm.

Nasıl bozuluyor?

  • Herkes için tek sayı. Bütün servislerin ortalamasına tek SLO koymak. Emir servisinin kötü günü, rapor servisinin iyi günüyle ortalanıp kayboluyor.
  • %100 hedefi. Sıfır bütçe demek, hiçbir değişikliğe izin yok demek. Pratikte ya hiç çıkamazsın ya da hedefi herkes yok sayar.
  • İstisna enflasyonu. Freeze sırasında “bu özellik çok önemli” diye çıkan her iş, bir sonraki freeze’i daha zayıf yapar. Bizde istisna listesi üç satır ve dördüncüsü yok.
  • Sessiz bütçe. Bütçenin %10’u bile harcanmıyorsa bu da bir sinyal: hedef fazla gevşek ya da çok yavaş çıkıyorsun. Bütçe harcanmak için var.

Bende işe yaramayanlar

  • Uptime’ı SLI yapmak. İlk hâlimiz buydu: %99,98. Müşterinin gördüğü %99,77 idi. Aradaki fark, ölmek üzere olan ama hâlâ “ayaktayım” diyen pod’lardı.
  • Freeze’i 30 günlük pencereye bağlamak. İlk yazdığımız politika “bütçe %100’ün altına inince freeze biter” diyordu. Kayan pencerede kötü günler 30 gün boyunca pencerede kalır; bu kural bizi bir ay kilitleyecekti. Bitişi kök neden düzeltmesine ve son 7 günün hızına bağladık.
  • “Kalan bütçe %50” alarmı. Hem geç hem gürültülü. Bütçenin yarısı iki ayrı olaydan da gidebilir, tek bir sızıntıdan da. Alarmın cevaplaması gereken soru “ne kadar kaldı” değil, “ne kadar hızlı gidiyor”.

Ne izlemeli?

NeNeden
30 günlük bütçe tüketimi (servis başına)Planlamanın ilk sorusu: bu servis bu çeyrek risk alabilir mi?
Kötü isteğin kaynağa göre dağılımıDeploy mu, bağımlılık mı, altyapı mı? Güvenilirlik işinin sırasını bu belirler
Deploy başına harcanan bütçeBizde 2.150 kötü istekten ~200’e indi; en ucuz iyileştirme buradaydı
Freeze sayısı ve süresiHiç yoksa hedef gevşek olabilir; sık oluyorsa hedef ya da mimari yanlış
SLI ile destek şikâyetleri arasındaki uyumSLI iyiyken şikâyet artıyorsa yanlış şeyi ölçüyorsun

Kontrol listesi

SLO’n gerçekten çalışıyor mu?
  • SLI kullanıcının gördüğü şeyi mi ölçüyor, sunucunun ayakta olmasını mı?
  • SLI yük dengeleyiciden mi ölçülüyor, uygulamanın kendi logundan mı?
  • Hedefin ayda kaç dakika ve kaç istek ettiğini hesapladım mı?
  • Hedef bugünkü gerçeğe yakın mı, yoksa bir dilek mi?
  • Bütçe bitince ne olacağı yazılı mı, ürün tarafı imzaladı mı?
  • Freeze’in nasıl biteceği yazılı mı?
  • İstisna listesi kaç satır? Geçen freeze’de kaç istisna çıktı?
  • Alarm eşiğe mi kurulu, yanma hızına mı?
  • Son planlamada bütçe tablosu masadaydı mı?

Sonuç

Temmuz’daki o 50 dakikalık tartışmada ikimiz de haklıydık ve ikimiz de ispatlayamıyorduk. Ürün yöneticisi müşterinin yeni özellik istediğini biliyordu. Ben servisin kırılgan olduğunu biliyordum. Eksik olan bilgi değil, ortak bir birimdi.

Hata bütçesi o birimi verdi. Bugün emir servisinin 30 günlük tüketimi %39. Bu çeyrek planlamasında kimse güvenilirlik için sprint istemedi; bütçe yeterince doluydu ve özellikler çıktı. Aynı sayı Eylül’de de freeze’i başlattı.

SLO’yu bir hedef gibi koyarsan tutturmaya çalışırsın. Bir anlaşma gibi koyarsan onunla karar verirsin. Fark şu: hedef “ne kadar iyiyiz” diye sorar, bütçe “şimdi ne yapıyoruz” diye.