1 puan yazan GN⁺ 2025-12-09 | 1 yorum | WhatsApp'ta paylaş
  • NATS JetStream dağıtık mesajlaşma sisteminin dayanıklılığını ve tutarlılığını Jepsen, çeşitli arıza senaryolarında doğruladı
  • Testlerde dosya bozulması (.blk, snapshot) ve güç kesintisi simülasyonu sırasında hem veri kaybı hem de split-brain durumu meydana geldi
  • JetStream varsayılan olarak fsync işlemini her 2 dakikada bir yaptığından, en son onaylanan mesajların diske yazılmamış halde kalması mümkündür
  • Tek bir düğümdeki OS çökmesi bile veri kaybı ve replikasyon tutarsızlığına yol açabilir
  • Jepsen, NATS için varsayılan ayarın fsync=always olarak değiştirilmesini veya veri kaybı riskinin açık bir şekilde belgelenmesini öneriyor

1. Arka Plan

  • NATS, mesajları stream olarak yayımlayıp abone olunan popüler bir streaming sistemidir
    • JetStream, verileri çoğaltmak için Raft mutabakat algoritmasını kullanır ve en az bir kez (at-least-once) teslimat garantisi sağlar
  • JetStream, belgelerinde linearizable tutarlılık ve her zaman kullanılabilirlik iddiası taşısa da, CAP teoremi gereği bu ikisi aynı anda sağlanamaz
  • NATS belgelerine göre 3 düğümlü streamler 1, 5 düğümlü streamler ise 2 sunucu kaybına dayanabilir
  • Mesajlar, sunucunun publish isteğini acknowledge ettiği anda “başarıyla kaydedildi” sayılır
  • Verinin tutarlı olması için quorum (çoğunluk) düğüm sayısı gerekir ve 5 düğümlü bir kümede yeni bir mesajın kaydedilmesi için en az 3 düğümün aktif olması gerekir

2. Test Tasarımı

  • Jepsen, JNATS 2.24.0 istemcisi ve Debian 12 LXC container ortamında testler gerçekleştirdi
    • Bazı testlerde Antithesis ortamında resmi NATS Docker image kullanıldı
  • Tek bir JetStream stream (replica 5) kuruldu ve süreç durdurma, çökme, ağ bölünmesi, paket kaybı, dosya bozulması gibi arızalar enjekte edildi
  • fsync edilmemiş yazıların kaybolmasını canlandırmak için LazyFS dosya sistemiyle güç kesintisi simülasyonu yapıldı
  • Her süreç benzersiz mesajlar yayımladı ve test bittikten sonra tüm düğümlerde onaylanan mesajların varlığı doğrulandı
  • Bir mesajın yalnızca bazı düğümlerde bulunması durumunda divergence (replica tutarsızlığı) olarak sınıflandırıldı

3. Temel Bulgular

3.1 NATS 2.10.22'de Tüm Veri Kaybı (#6888)

  • Yalnızca basit bir süreç çökmesiyle JetStream streaminin tümünün kaybolduğu durum tespit edildi
  • "No matching streams for subject" hatası oluştu ve saatlerce düzeltilmedi
  • Nedeni lider snapshot ters yönlendirmesi, Raft durumunun silinmesi vb olarak bulundu ve 2.10.23 sürümünde düzeltildi

3.2 .blk Dosya Bozulmasında Veri Kaybı (#7549)

  • JetStream'in .blk dosyasında tek bit hatası veya truncation (kırpma) oluştuğunda yüz binlerce onaylı yazma kayboldu
    • Örn: 1,367,069 üzerinden 679,153 kayıp
  • Sadece bazı düğümler bozulsa bile büyük ölçekte veri kaybı ve split-brain görüldü
    • Örn: n1, n3, n5 düğümlerinde en fazla %78 mesaj kaybı
  • NATS, bu konuyu inceleme aşamasında

3.3 Snapshot Dosyası Bozulduğunda Tüm Verinin Silinmesi (#7556)

  • data/jetstream/$SYS/_js_/ içindeki snapshot dosyası bozulduğunda, düğüm streami orphaned (sahipsiz) kabul edip tüm veriyi siliyor
  • Sadece birkaç düğüm bozulsa bile küme çoğunluğuna ulaşılamaması ve streamin kalıcı olarak kullanılamaz hale gelmesi oluşuyor
  • Örn: n3, n5 bozulduğunda → n3 lider seçildi ve jepsen-stream tamamen silindi
  • Jepsen, lider seçiminde bozulmuş bir düğümün lider olma riskini vurguluyor

3.4 Varsayılan fsync Ayarından Kaynaklanan Veri Kaybı (#7564)

  • JetStream varsayılan olarak yalnızca 2 dakikada bir fsync çalıştırır ve mesajları anında onaylar
    • Böylece en yeni onaylı mesajlar diske yazılmamış kalabilir
  • Güç kesintisi veya kernel çökmesi durumunda onlarca saniyelik onaylı mesaj kaybı görülür
    • Örn: 930,005 üzerinden 131,418 kayıp
  • Tekil düğüm arızası ardışık şekilde olsa bile tüm streamin silinmesi mümkündür
  • Bu davranış belgelerde neredeyse hiç yer almıyor
  • Jepsen, fsync=always varsayılanının değiştirilmesini veya veri kaybı riskine ilişkin açık uyarı verilmesini tavsiye ediyor

3.5 Tek Bir OS Çökmesi Nedeniyle Oluşan Split-Brain (#7567)

  • Tek bir düğümdeki yalnızca güç kesintisi veya kernel çökmesi bile veri kaybı ve replikasyon tutarsızlığına neden olabilir
  • Lider-izleyici mimarisinde bazı düğümlerde yalnızca bellekte commit edilmiş bir onay sonrası arıza yaşanırsa,
    çoğunluk düğüm kaybı yaşar ve yeni bir duruma geçilir
  • Testte tek bir güç kesintisi sonrası süreğen split-brain gözlendi
    • Düğüm bazında farklı aralıklarda onaylı mesaj kayıpları görüldü
  • Jepsen, benzer bir örneği Kafka'dan alıntılayarak Raft tabanlı sistemlerde de aynı riskin bulunduğunu vurguluyor

4. Tartışma ve Sonuç

  • 2.10.22'deki tam veri kaybı sorunu, 2.10.23 ile giderildi
  • 2.12.1'de ise dosya bozulması ve OS çökmesi nedeniyle veri kaybı ve split-brain hâlâ gözleniyor
  • .blk ve snapshot dosyaları bozulduğunda bazı düğümlerde mesaj atlaması veya tüm streamin silinmesi oluşuyor
  • Varsayılan fsync aralığının uzunluğu nedeniyle birden fazla düğüm aynı anda arızalandığında onaylı verinin kaybolma riski devam ediyor
  • Jepsen, fsync=always ayarı veya belgelerde net bir risk notu eklenmesini öneriyor
  • JetStream'in “her zaman kullanılabilir” iddiası CAP teoremi açısından imkansız, belge güncellemesi gerekli
  • Jepsen ayrıca, hata varlığının kanıtlanabilir ancak güvenliksizlik iddiasının kanıtlanamaz olduğunu belirtiyor

4.1 LazyFS'nin Rolü

  • LazyFS kullanılarak fsync edilmemiş yazıların kaybı simüle edildi
  • Güç kesintisi sırasında kısmi yazı bozulması (torn write) gibi farklı depolama hataları tekrarlanabiliyor
  • İlgili çalışma When Amnesia Strikes (VLDB 2024)’te, PostgreSQL, Redis, ZooKeeper gibi sistemlerde de benzer hatalar rapor edildi

4.2 Gelecekteki Çalışmalar

  • Tekil tüketici seviyesinde mesaj kaybı, mesaj sırası ve linearizable/serializable garantilerinin doğrulaması henüz yapılmadı
  • exactly-once teslimat garantisi gelecekteki çalışmaların konusu olacak
  • Düğüm ekleme/çıkarma sırasında belge hataları ve zorunlu health check adımının atlanması tespit edildi (#7545)
  • Güvenli bir cluster yeniden yapılandırma akışı henüz net değil

1 yorum

 
GN⁺ 2025-12-09
Hacker News görüşleri
  • Birileri karmaşık teoriyi es geçip böyle sistemler yaptığında, aphyr’in gelip onu dağıttığını görmek artık alışıldık bir şey
    Şimdi merak ettiğim şu: Acaba yapay zeka bir projenin dokümantasyonunu okuyup veri kaybı olasılığını sadece pazarlama dili üzerinden tahmin edebilir mi?
    • Uzun sakalını sıvazlayarak başını sallayan biri gibi hissediyorum
      İnsanlar hep “teori abartılıyor” ya da “okul eğitimi yerine hacklemek daha iyidir” der, ama sonunda dönüp dolaşıp belgelenmiş problem alanında kendi kendilerine çelme takarlar
    • Ben de LLM’e benzer bir şey yaptırmıştım ve sonuç oldukça faydalıydı
  • NATS sanki CAP teoremini görmezden geliyor gibi hissettiriyor
    • Bu, değeri bilinmeyen bir tespit gibi duruyor
  • Ben NATS’i in-memory pub/sub amacıyla kullandım ve o konuda harikaydı
    İnce ölçeklenme detaylarını da iyi hallediyordu
    Ama persistence tarafını hiç kullanmadım ve bu kadar kırılgan olabileceğini bilmiyordum
    Tek bir bitlik dosya bozulmasına bile açık olması şaşırtıcı
  • İlgili bir kaynak olarak, Jepsen ve Antithesis kısa süre önce bir dağıtık sistemler sözlüğü yayımladı
    Başvuru için çok iyi bir kaynak → Jepsen Glossary
  • aphyr.com/tags/jepsen ile jepsen.io/analyses arasındaki içerik farkını merak etmiştim
    aphyr.com’u yakın zamanda keşfettim; bol içgörü sunacak gibi görünüyor, o yüzden umutluyum
    • Jepsen aslında bir kişisel blog serisi olarak başlamıştı
      Sonrasında jepsen.io bir profesyonel projeye dönüştü ve yaklaşık 10 yıl önce ciddi biçimde işletilmeye başlandı
  • “Lazy fsync by Default” ayarının neden var olduğunu merak ediyorum
    Sebebi benchmark performansını yükseltmek mi? Küçük kümelerde bu tür ayarlar sık sık sorunun kaynağı oluyor
    • Bunun sadece gecikmeye değil, throughput artışına da etkisi var
      Pek çok uygulama tam dayanıklılık gerektirmediğinden lazy fsync faydalı olabilir
      Ama bunu varsayılan yapmak tartışmalı
    • fsync’in neden mutlaka geciktirilmesi gerektiğini hep merak etmişimdir
      TCP corking gibi toplu işleme (batch) ile çözülebilir gibi geliyor
    • Dağıtık sistem olunca yapılabilen şeylerden biri bu
      Çünkü lazy fsync kaynaklı başarısızlıklar genelde düğümlerin çoğunda aynı anda yaşanmaz
    • Evet, bu performans kazanımı için yapılan bir tercih
    • Replikasyon ve dağıtım üzerinden dayanıklılık, lazy fsync ile de throughput elde edilmeye çalışılıyor
  • JetStream için sunucusuz bir alternatif olarak s2.dev öneriliyor
    Artıları: nesne depolama düzeyinde dayanıklılığa sahip sınırsız stream desteği
    Eksileri: henüz consumer group özelliği yok
    • Bunun üzerinde hiç Jepsen testi çalıştırıldı mı diye merak ediyorum
  • Sorun şu ki NATS varsayılan olarak yalnızca 2 dakikada bir fsync yapıyor ve ack’i hemen döndürüyor
    Birden fazla düğüm aynı anda arıza yaşarsa commit edilmiş veriler kaybolabiliyor
    Bu bana MongoDB’nin ilk dönemlerindeki “web scale” pazarlamasını hatırlatıyor
    Bence varsayılanlar her zaman en güvenli seçenek olmalı
    • NATS, yalnızca küme kullanılabilirliğini garanti ettiğini açıkça belirtiyor
      Bu benim aslında hoşuma gitmişti; üzerine sistem tasarlayabiliyordum
      2018’de kullandığımda hem hızlıydı hem de yönetmesi kolaydı
    • Çoğu modern veritabanının varsayılanları da tamamen güvenli değil
      Örneğin PostgreSQL’in varsayılan transaction isolation seviyesi read committed
      Redis de varsayılan olarak her 1 saniyede bir fsync yapıyor
    • Redis cluster, ancak veri çoğunluk düğümlere replike edildikten sonra ack döndürür
      Standalone Redis’te de fsync sonrası ack ayarı yapılabilir ama OS buffering yüzünden tam garanti zordur
      Sonuçta önemli olan ack’in anlamını doğru anlamak
    • Çoğu sistem hız ile dayanıklılık arasında ödünleşim seçiyor
      Sadece güvenli varsayılanlarda ısrar edilirse performans ciddi şekilde düşer ve kullanıcıların her şeyi elle ayarlaması gerekir
      Mesela Postgres’in varsayılan isolation seviyesi de zayıf olduğu için race condition oluşabilir
      Referans: Hermitage test yazısı
    • Sorun şu ki fsync neredeyse sadece uç seçenekler sunuyor
      SSD çağında group-commit gibi ara aşamalar kayboldu; şimdi darboğaz syscall geçiş maliyeti
      2 dakika ise fazlasıyla uzun bir süre (fdatasync ile fsync farkı da hesaba katılmalı)
  • Açıkçası bunu bekliyordum ama durumun bu kadar ciddi olacağını düşünmemiştim
    Sanırım gidip Redpanda kullanmak daha iyi
  • NATS’in fsync performans uyarısını iyileştirmenin bir yolu olup olmadığını merak etmiştim
    Belirli aralıklarla batch flush yapılırsa gecikme artsa da throughput korunabilir diye düşünüyorum
    • Sabit bir aralık yerine, fsync sürerken yazma istekleri kuyruğa alınarak bir sonraki batch ile birlikte işlenebilir
      Bu, Paxos round’larını birleştirmeye benziyor
      Bir round biter bitmez sıradaki batch’in hemen başlatılması gerekir