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

Ana sayfa → Teknik

Canlıya Çıkmak: Deploy Değil, Sürüm Yönetimi

Cuma 15:40, yeni ödeme akışı canlıda. 15:58’de hata oranı %0,4’ten %6’ya çıktı. Geri alma başlattık; 9 dakika sürdü. O 9 dakikada 1.100 kullanıcı ödeme ekranında takıldı. Aynı değişiklik bir flag’in arkasında olsaydı kapatması 4 saniye sürecekti. Flag yoktu.

Özet
  • Deploy ile sürüm aynı şey değil. Deploy kodu sunucuya koyar, sürüm kullanıcıya gösterir. Aynı anda olmaları tesadüf olmalı, kural değil.
  • Geri alma süren, en yavaş geri alma yolun kadardır. Deploy’u geri almak dakikalar, flag kapatmak saniyeler sürer.
  • Dört ayrı flag tipi var, ömürleri farklı. Hepsini tek torbaya atarsan hiçbirini silemezsin.
  • Flag mezarlığı gerçek bir borç. 61 flag’imiz vardı, 23’ü bir yıldan eskiydi; ikisi birbiriyle çelişiyordu.
  • Silme tarihi flag açılırken yazılır. Sonradan temizlik kampanyası yapmak işe yaramıyor; CI’ın uyarması gerekiyor.
  • Kademeli çıkışın eşiği insana bırakılmaz. İnsana bırakılan eşik, gece 03:00’te çalışmayan eşiktir.

Sahadan: 9 dakika ile 4 saniye

O cuma yaptığımız şey teknik olarak doğruydu: hata fark edildi, karar verildi, sürüm geri alındı, sistem düzeldi. Kimse panik yapmadı. Yine de 9 dakika kaybettik ve bu 9 dakikanın tamamı kaçınılabilirdi.

Sebep şu: değişikliği canlıya çıkarmanın tek yolu deploy’du, dolayısıyla geri almanın da tek yolu deploy’du. Deploy bir yapı işidir — imaj çekilir, pod’lar değişir, sağlık kontrolleri beklenir. Hızlandırabilirsin ama saniyeye indiremezsin. Oysa “bu özelliği kullanıcıya gösterme” kararı bir okuma işidir; bir değerin okunmasıdır ve saniyeler sürer.

Ertesi hafta aynı akışı flag arkasında yeniden çıkardık. Üç gün kapalı kaldı, sonra %5 kullanıcıya açtık. İkinci günün sabahında aynı hata sınıfı tekrar göründü — bu sefer kapatmak bir alan değişikliğiydi, etkilenen kullanıcı sayısı 40 civarıydı. Aynı hata, iki farklı maliyet.

Deploy bir mühendislik olayı, sürüm bir ürün kararıdır. İkisini aynı ana bağlarsan, ürün kararını geri almak için sunucu beklemen gerekir.

Deploy ≠ sürüm

DeploySürüm
Ne yaparKodu sunucuya koyarKullanıcıya gösterir
Kim karar verirMühendis / pipelineÜrün + mühendis birlikte
Ne kadar sürerDakikalarSaniyeler
Geri almaYeni deployBir değeri değiştirmek
RiskiTeknik (çalışıyor mu?)Ürün (doğru şey mi?)
Ne sıklıktaGünde birçok kezHazır olduğunda

Bu ayrımın en sevdiğim yan etkisi şu: ikisi ayrıldığında “bu iş yetişmeyecek, sürümü kaydıralım” tartışması bitiyor. Kod çıkar, kapalı durur, hazır olduğunda açılır. Yarım kalan işi bir dalda bekletmek zorunda kalmıyorsun — ki bekleyen dal, birleşirken en çok çatışan daldır.

Not: deploy’u sıklaştırmanın neden bu kadar önemli olduğunu ve deploy treninin ekipleri nasıl kilitlediğini monolitten mikroservise yazısında anlatmıştım; burada tekrar etmiyorum.

Dört flag tipi, dört ömür

“Feature flag” tek bir şey değil. Hepsini aynı listede tutmak, silme kuralını imkânsızlaştırıyor — çünkü biri “ama bazıları kalıcı” deyince bütün temizlik duruyor. Dört tip ve beklenen ömürleri:

Tipler
1) SURUM FLAG'I      : yeni ozelligi kademeli acmak
   omur: gunler-haftalar   --> acildiktan sonra SILINIR

2) KILL SWITCH       : bir ozelligi acil kapatma kolu
   omur: kalici            --> silinmez, ama YILDA BIR test edilir

3) DENEY (A/B)       : iki varyanti karsilastirmak
   omur: deney suresi      --> sonuc cikinca SILINIR

4) IZIN / SEGMENT    : "bu musteri bu ozelligi kullanabilir"
   omur: kalici            --> aslinda flag degil, yetkilendirme;
                               flag sisteminde durmamali

Dördüncü tip bizde en çok karışan yerdi. “Kurumsal müşteriler şu ekranı görebilir” bir sürüm kararı değil, bir yetkilendirme kuralı. Flag sisteminde tuttuğun sürece hem silinemiyor hem de flag sayısını şişiriyor. Ayırdığımızda 61 flag’in 14’ü tek hamlede listeden çıktı.

Flag mezarlığı ve silme kuralı

Flag açmak bir kişinin beş dakikasını alıyor; silmek ise kimsenin işi değil. Sonuç tahmin edilebilir: bizde 61 aktif flag vardı, 23’ü bir yıldan eskiydi. İkisi birbiriyle çelişiyordu — biri yeni akışı açıyor, diğeri eski akışı zorluyordu; hangi kullanıcının hangisini gördüğü kodu okumadan bilinmiyordu.

Temizlik kampanyası denedik, işe yaramadı. İşe yarayan şey, kararı flag’i açarken almaktı:

İşe yaramayan
  • Çeyrek sonu “flag temizliği” sprint’i
  • Wiki’de flag envanteri tutmak
  • “Sahibi kim?” diye etiket eklemek

Üçü de hatırlamaya dayanıyor. Hatırlamaya dayanan hiçbir kural üç ay yaşamıyor.

İşe yarayan
  • Flag tanımında zorunlu silme_tarihi alanı
  • Tarihi geçince CI uyarı üretir
  • İki hafta sonra CI derlemeyi kırar
  • Kalıcı tipler (kill switch, izin) kuraldan muaf, ayrı işaretli

Karar, flag açılırken ve bir satırda veriliyor. Kimsenin hatırlaması gerekmiyor.

Sert gelebilir ama derlemeyi kırma kısmı şart. Sadece uyarı verdiğimiz iki ay boyunca hiçbir flag silinmedi; uyarılar listenin dibine düştü. Kırmaya başladığı hafta 18 flag temizlendi.

Hatırlamaya dayanan kural, kural değildir. Üç ay sonra kimse hatırlamıyor.

Kademeli çıkış: eşiği önceden yaz

Kademeli çıkışı “önce az kullanıcıya açalım, bakarız” diye yapmak, yapmamakla neredeyse aynı. “Bakarız” kimin bakacağını, ne kadar bakacağını ve neye bakacağını söylemiyor. Adımları yazılı hâle getirdik:

Cikis plani
ADIM   TRAFIK   EN AZ SURE   OTOMATIK GERI ALMA ESIGI
-----------------------------------------------------------
  1      %1       15 dakika    hata orani > %1  VEYA  p95 > 800ms
  2      %5       30 dakika    hata orani > %1  VEYA  p95 > 800ms
  3     %25        2 saat      ayni
  4    %100          -         ayni  (24 saat izlenir)

KURAL: esik asilirsa otomatik geri alinir, kimse onay vermez.
       Gece 03:00'te insana sorulan esik, calismayan esiktir.
KURAL: bir adim atlanamaz; "acelesi var" diyen adimi atlatamaz,
       adimlarin suresini kisaltabilir ve bunu yaziyla yapar.

İki ayrıntı önemli. Birincisi en az süre: yüzdeyi artırmak için “sorun görünmüyor” yetmiyor, en az o kadar beklemek gerekiyor. Çoğu sorun trafikle değil, zamanla ortaya çıkıyor — bellek sızıntısı, dolan bir kuyruk, birikmiş bir tablo. İkincisi otomatiklik: eşiği insana bırakırsan, eşik yalnızca birinin uyanık olduğu saatlerde çalışır.

Nöbetçinin gece bir flag’i tek başına kapatabilmesi de bu düzenin parçası; nöbet yazısında “geri alınabilir işler gece serbesttir” derken kastettiğim şeylerden biri bu.

Ne izlemeli?

NeNedenBizde ne oldu
Geri alma süresi (en yavaş yol)Gerçek risk bu; ortalama değil, en kötü yol ölçülür9 dk → flag’li akışlarda saniyeler
Sürümlerin kaçı flag arkasındaDüşükse her hata bir deploy geri alması demekHedef: kullanıcıya görünen her değişiklik
Açık flag sayısı ve en eskisinin yaşıYaş, borcun faizi; sayı tek başına yanıltıcı61 flag / en eski 14 ay → 30 / 3 ay
Kademeli çıkışta yakalanan hata oranı%100’e gitmeden yakalananlar, sistemin kazandığı tek şeyYakalanmayan her hata bir plan boşluğu

Bende işe yaramayanlar

  • Flag’i kod içinde if ile dağıtmak. Başta pratik geldi. Altı ay sonra aynı flag yedi yerde okunuyordu ve biri eski varsayılanı kullanıyordu. Flag okuma tek bir yerden geçmeli; dallanma değil, kararın kendisi merkezî olmalı.
  • “Önemli değişikliklerde kademeli çıkarız.” “Önemli”yi kim belirliyor? Kimse. Sonuçta en sessiz görünen değişiklik — bir yapılandırma satırı — en büyük kesintiyi yaptı. Şimdi kural tersine: kullanıcıya görünen her şey kademeli çıkar, istisna yazıyla istenir.
  • Mavi-yeşil (blue-green) ile işi bitirmiş sanmak. Trafiği anında çevirmek güzel ama ya hep ya hiç. %1’lik bir dilime çıkamıyorsan, hatayı bütün kullanıcılarda keşfediyorsun demektir. İkisi birbirinin alternatifi değil; mavi-yeşil altyapı, kademeli çıkış karar katmanı.

Kontrol listesi

Çıkmadan önce
  • Bu değişikliği geri almanın en hızlı yolu ne, kaç saniye sürüyor?
  • Kullanıcıya görünen kısım bir flag’in arkasında mı?
  • Flag’in tipi ve silme tarihi yazılı mı?
  • Kademeli çıkış adımları, süreleri ve eşikleri önceden belli mi?
  • Eşik aşılınca geri alma otomatik mi, yoksa birinin onayını mı bekliyor?
  • Nöbetçi bu flag’i gece tek başına kapatabilir mi?
  • Veri tarafı geriye dönük uyumlu mu — eski ve yeni sürüm bir süre yan yana çalışacak?
  • Şu an kaç açık flag var, en eskisi kaç aylık?

Sonuç

O cuma sorun yeni ödeme akışının hatalı olması değildi; her akış bir gün hatalı olur. Sorun, hatayı geri almanın tek yolunun sunucu beklemek olmasıydı. Kodu çıkarmakla kullanıcıya göstermeyi aynı ana bağlamıştık, o yüzden ürün kararını geri almak için bir yapı işlemi çalıştırmak zorunda kaldık.

Sürüm yönetimi, hata yapmamak için değil, hatanın maliyetini seçebilmek için var. Aynı hata 1.100 kullanıcıya da çıkabiliyor 40 kullanıcıya da; farkı yaratan kodun kalitesi değil, çıkış düzeni.

Tek soruyla ölç: şu an canlıdaki en son değişikliği geri almak kaç saniye sürer? Cevap dakikaysa, sürüm yönetimin yok; deploy’un var.