Jepsen: NATS 2.12.1
(jepsen.io)- 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
fsynciş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=alwaysolarak 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
publishisteğ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
fsyncedilmemiş 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
.blkdosyası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,n5düğümlerinde en fazla %78 mesaj kaybı
- Örn:
- 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,n5bozulduğunda →n3lider seçildi vejepsen-streamtamamen 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=alwaysvarsayı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
.blkve snapshot dosyaları bozulduğunda bazı düğümlerde mesaj atlaması veya tüm streamin silinmesi oluşuyor- Varsayılan
fsyncaralığının uzunluğu nedeniyle birden fazla düğüm aynı anda arızalandığında onaylı verinin kaybolma riski devam ediyor - Jepsen,
fsync=alwaysayarı 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
fsyncedilmemiş 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
Hacker News görüşleri
Ş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?
İ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
İ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ı
Başvuru için çok iyi bir kaynak → Jepsen Glossary
aphyr.com’u yakın zamanda keşfettim; bol içgörü sunacak gibi görünüyor, o yüzden umutluyum
Sonrasında jepsen.io bir profesyonel projeye dönüştü ve yaklaşık 10 yıl önce ciddi biçimde işletilmeye başlandı
Sebebi benchmark performansını yükseltmek mi? Küçük kümelerde bu tür ayarlar sık sık sorunun kaynağı oluyor
Pek çok uygulama tam dayanıklılık gerektirmediğinden lazy fsync faydalı olabilir
Ama bunu varsayılan yapmak tartışmalı
TCP corking gibi toplu işleme (batch) ile çözülebilir gibi geliyor
Çünkü lazy fsync kaynaklı başarısızlıklar genelde düğümlerin çoğunda aynı anda yaşanmaz
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
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ı
Bu benim aslında hoşuma gitmişti; üzerine sistem tasarlayabiliyordum
2018’de kullandığımda hem hızlıydı hem de yönetmesi kolaydı
Örneğin PostgreSQL’in varsayılan transaction isolation seviyesi read committed
Redis de varsayılan olarak her 1 saniyede bir fsync yapıyor
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
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ı
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ı)
Sanırım gidip Redpanda kullanmak daha iyi
Belirli aralıklarla batch flush yapılırsa gecikme artsa da throughput korunabilir diye düşünüyorum
Bu, Paxos round’larını birleştirmeye benziyor
Bir round biter bitmez sıradaki batch’in hemen başlatılması gerekir