Olay odaklı sistemler (event-driven systems) kurarken, çoğu geliştirici 'en az bir kez teslimat' (at-least-once delivery) prensibini benimser: iş tamamlanana kadar yeniden dene ve aşağı akıştaki her şeyi idempotent olarak tasarla. Bu iyi bir tavsiyedir, ancak altında gizlenen sinsi bir hata türü vardır. Sistem başarıyı bildirir, ilerlemeyi kaydeder ve işi sessizce yere düşürür. Hiçbir istisna, uyarı veya ölü mektup kuyruğu oluşmaz. Sadece bir mesajın yapması gereken iş yapılmamıştır.
Bu sorunla yakın zamanda karşılaştım: küçük bir yüzdedeki olayların gizemli bir şekilde işlenmediğini fark ettim. Her şey sağlıklı görünüyordu. Üretici 2xx yanıtı aldı. Tüketici ofsetini işledi. Gösterge panelleri yeşildi. Ancak iş hiç gerçekleşmedi. Bu yazı, 'sistem isteğimi kabul etti' ile 'sistem işi gerçekten yaptı' arasındaki boşluğu ve bunun dağıtık sistemlerde veri kaybına yol açan en tehlikeli noktalardan biri olduğunu ele alıyor.
Çoğu mesaj işleme güvenilirliği yazısı, yinelenen teslimat, sıra dışı mesajlar, zehirli mesajlar ve tüketici gecikmesi gibi bilinen tehlikelere odaklanır. Bunlar gerçektir ve haklarında çok şey yazılmıştır. Ancak çok daha az tartışılan bir durum vardır: onaylamanın kendisinin bir yalan olduğu durum. Bir bileşen, yalnızca kabul edilmiş ancak tamamlanmamış bir işlem için başarı bildirir ve ikinci bir bileşen bu onayı orijinal mesajı atmak için izin olarak kullanır.
Teknik Analiz
Bu, bir kuyruk tüketicisinin asenkron bir API çağırması, bir iş akışı motorunun bir işi sıraya koyması veya bir hizmetin işi bir arka plan çalışanına devretmesi gibi birçok yığında görülen bir tasarım kokusudur. Asenkron bir sınır boyunca her el değiştirmede bu boşluğun oluşma potansiyeli vardır. Bu hatanın anatomisini temel ilkelerden inceleyelim ve ardından nasıl düzgün bir şekilde kapatılacağını tartışalım.
Sorunu anlamak için iki tür 'evet' yanıtını ayırt etmek önemlidir. Bir sistem isteğinize yanıt verdiğinde, iki çok farklı anlama gelebilir: 'İsteğinizi kabul ettim' (HTTP 202 Accepted) veya 'İsteğinizi tamamladım' (200 OK). Bu ikisini birbirine karıştırmak birçok sorunun kök nedenidir. Sorun şu ki, birçok API, işin sonunda başarılı olup olmayacağına bakılmaksızın 'kabul edildi' için aynı durum kodunu döndürür. Tüketici tarafında ise, Apache Kafka gibi ofset tabanlı tüketici grupları kullanan brokerlar vardır. Ofset işleme, 'bu mesaja kadar her şey tamamen işlendi' anlamına gelir. Bu ifade doğru değilse, veri kaybına neden olursunuz.
Hata şu şekilde oluşur: Tüketici bir mesaj okur ve bir kontrol düzlemine asenkron bir iş oluşturma isteği gönderir. Kontrol düzlemi 204 No Content yanıtı verir. Tüketici bunu başarı olarak görür ve ofseti işler. Ancak, tüketicinin görüş alanı dışında, kontrol düzlemi işi yürütülmeden önce reddeder (örneğin, eşzamanlılık kotası aşıldığı için). İş hiçbir iş mantığı çalıştırılmadan 'reddedildi' durumuna geçer. Tüketici ofseti işlediği için, mesaj bir daha asla teslim edilmez. İş sessizce kaybolur. Bu 'onaylama boşluğu' (acknowledgment gap) olarak adlandırılır ve dağıtık sistemlerde veri kaybının sinsi bir nedenidir. Çözüm, tüketicinin yalnızca işin tamamlandığını doğruladıktan sonra ofseti işlemesini sağlamaktır; bu da genellikle iki aşamalı bir işleme veya işin durumunu izleme mekanizması gerektirir.
Kaynak: dev.to