Mikroservis mimarilerinin ortaya çıkışı, geleneksel ACID garantilerinin imkansız olduğu hizmet sınırları arasında dağıtılmış işlemleri yönetmek için Saga deseninin gerekliliğini doğurmuştur. Tarihsel olarak, testler anında tutarlılıkla monolitik veritabanlarına dayanıyordu, ancak modern poliglot sistemler, eşzamansız iş akışlarının ve telafi mantığının doğrulanmasını gerektiriyor. Ana sorun, geleneksel entegrasyon testlerinin senkron yanıtları varsaymasıdır; bu, yarış koşullarını, ağ bölünmelerini ve bazı saga katılımcılarının başarılı olurken diğerlerinin başarısız olduğu durumları yakalamakta yetersiz kalır.
Çözüm, test araçlarına entegre edilmiş bir Chaos Engineering yaklaşımını gerektirir. Gerçek PostgreSQL, MongoDB ve Redis örneklerini izole Docker ağları içinde düzenlemek için Testcontainers kullanan bir çerçeve mimarlayın. Toxiproxy'yi, saga adımlarında gecikme, bant genişliği kısıtlamaları ve ağ bölünmesi enjekte etmek için hizmetler arasında programlanabilir bir TCP proxy olarak tanıtın. Statik uyku yerine anlık beklemeler için Awaitility kullanın ve tam yürütme yollarını yeniden oluşturmak için dağıtık izleme amacıyla Jaeger'i entegre edin. Telafilerin kesin bir şekilde bir kez gerçekleştirildiğini doğrulamak için UUID tabanlı idempotentlik anahtarı takibi uygulayın ve tüm kalıcı katmanlar arasında durumları anlık görüntüleyen bir GlobalConsistencyValidator inşa edin.
Bağlam: Çok uluslu bir e-ticaret platformu, Envanter Servisi (PostgreSQL), Ödeme Servisi (MongoDB ile işlem günlükleri) ve Gönderim Servisi (Elasticsearch) içeren olay tabanlı bir saga aracılığıyla siparişleri işledi. Mimari, Java tabanlı mikroservisler arasındaki koreografi için Apache Kafka kullandı.
Problem Açıklaması: Yoğun trafik sırasında, ağ kesintileri ödeme işlemlerinin başarılı olmasına neden olurken envanter rezervasyonunun başarısız olmasına neden oldu ve telafi sürecini tetikledi. Ancak, telafi mantığında, ilk geri ödeme isteği zaman aşımına uğradığında, idempotentlik sözleşmelerini ihlal eden, eşzamanlılık hatası içeren kritik bir yarış durumu vardı. Ayrıca, poliglot depolardaki nihai tutarlılık gecikmeleri, mevcut testlerde yanlış pozitif sonuçlara neden oldu, bu da hemen envanterin geri yüklenmesini talep eden flake CI/CD hatalarına ve mevcut olmayan ürünler için müşteri ücretlendirmelerine yol açtı.
Yaklaşım 1: Sabit Gecikmeli UI Tabanlı Uçtan Uca Test
Başlangıçta, kullanıcı ödeme akışlarını simüle etmek için Selenium WebDriver kullanmayı düşündük ve eşzamansız işleme için beklemek üzere Thread.sleep(5000) ekledik.
Artılar: Uygulaması basit, tam kullanıcı yolculuğunu kapsıyor ve hizmet kodunda herhangi bir değişiklik gerektirmiyor.
Eksiler: Aşırı derecede kırılgan; beş saniye yük altında yetersizdi ve boş zamanlarda aşırıydı. Ağ arızaları, belirli saga aşamalarında enjekte edilemedi, bu da belirli yarış durumunu yeniden üretmeyi imkansız hale getirdi. Bu yaklaşım, hizmetler arası HTTP iletişim desenleri veya veritabanı durum geçişleri hakkında görünürlük sağlamıyordu.
Yaklaşım 2: Bellek Üzerinde Veritabanları ile Sahte Birim Testi İkinci seçenek, tüm dış hizmet çağrılarını Mockito kullanarak taklit etmek ve her hizmetin birim testleri için H2 bellek içi veritabanı kullanmaktı. Artılar: 10 saniyenin altında çalışma süresi, altyapı bağımlılıkları yok ve izolasyonda belirleyici sonuçlar. Eksiler: Gerçek dünya serileştirme sorunlarını, TCP soket zaman aşımı davranışlarını veya PostgreSQL'de var olan ancak H2'de bulunmayan veritabanı spesifik kilitleme mekanizmalarını tespit edemedi. İdempotentlik yarış durumu, yalnızca gerçek ağ paket davranışı ve bağlantı havuzu tükenmesi ile ortaya çıkıyordu, bunları taklit etmek mümkün değil.
Yaklaşım 3: Gerçek Altyapı ile Orkestre Edilmiş Kaos (Seçilen) JUnit 5 ve Testcontainers kullanarak özel bir test aracı geliştirdik. Her hizmet, Toxiproxy'nin yönetiminde izole Docker konteynerlerinde çalışıyordu. API giriş noktaları için RestAssured kullanarak ve dış ödeme işlemcisinin idempotentlik davranışını simüle etmek için WireMock'ı kullandık. Artılar: Belirli saga adımlarında hassas hata enjektesi sağladı (örneğin, ödeme onaylandığında bağlantıyı kesmek ancak envanter kontrolünden önce). Awaitility, sabit beklemeler olmadan nihai tutarlılık için dinamik beklemeyi sağladı. Jaeger izleri, telafi yollarını doğrulamak için yürütme yollarının adli analizini sağladı. Eksiler: Daha yüksek başlangıç kurulum karmaşıklığı ve kaynak gereksinimleri (yerel yürütme için minimum 8GB RAM) ve birim testlere göre daha uzun başlangıç önyükleme süresi.
Sonuç: Çerçeve, telafi yeniden denemelerinin çifte anahtarlar için uygun HTTP 409 Çatışma işlemesinin eksik olduğu idempotentlik hatasını tespit etti. Geri ödeme talepleri göndermeden önce Redis idempotentlik anahtarlarını kontrol etmek için mantığı düzelttikten sonra, üretim çifte ücretlendirmeleri sıfıra düştü. Test yürütme süresi, 8 dakikadan (kırılgan UI testleri) 45 deseğe (hedeflenmiş entegrasyon testleri) düşerken, hata senaryoları kapsamı %300 oranında arttı.
Ağ arızaları beklenmedik istemci sonuçlarına neden olduğunda, telafi işlemlerinin idempotentliğini nasıl doğruluyorsunuz?
Adaylar genellikle yalnızca nihai hesap bakiyelerini doğrular, aşağı akış sistemlerinin tam olarak bir isteği aldığını kritik doğrulamayı atlarlar. Doğru uygulama, kaos enjekte edilmeden önce UUID idempotentlik anahtarını yakalamayı, ardından WireMock'ın verify(exactly(1), postRequestedFor()) yöntemini kullanarak yalnızca bir eşleşen isteğin ödeme geçidine ulaştığını doğrulamayı içerir. Ayrıca, geçişlerin COMPENSATING -> COMPENSATED olduğundan emin olmak için Saga Orkestratörü'nün durum makinesi kayıtlarını kontrol etmek gerekir, bu da gereksiz uyarılara neden olabilecek ara FAILED durumlarını tetiklememelidir. Bu, istek baytları gönderildikten sonra ancak yanıt baytları ulaşmadan bağlantıları kesmek için TCP düzeyinde proxy kontrolü gerektirir, bu da idempotentlik yönetimini test eden tam belirsiz zaman aşımı koşulunu yaratır.
Farklı çoğaltma gecikmelerine sahip heterojen veri havuzlarında nihai tutarlılığı doğrularken test kırılganlığını önlemek için hangi strateji uygulanır?
Birçok aday, sabit zaman aşımı ile anket önerir. Dayanıklı çözüm, Awaitility'yi, 100 ms'den başlayan ve prodüksiyon gecikmesinin 99. persentilinde (örneğin 3 saniye) tavanlanan üstel geri dönüş ile kullanır. Kritik olarak, testlerde, saga başlamadan önce PostgreSQL, MongoDB ve Redis üzerindeki mantıksal zaman damgalarını anlık görüntülemek için bir Global Clock veya Vector Clock mekanizması uygulayın. Sonuçlar daha sonra okuma işlemlerinin, saga başlangıç zamanından daha büyük veya ona eşit zaman damgaları döndürdüğünü doğrulamak için kontrol edilir. CQRS senaryoları için, veritabanlarını değiştirmek yerine, testlerde gömülü olarak bulunan Debezium kullanarak CDC olaylarına abone olun; bu da bekleme sürelerini saniyeden milisaniyelere indirir ve testlerin onaylanması ile veri çoğaltılması arasındaki yarış koşullarını ortadan kaldırır.
Bazı saga katılımcılarının taahhütte bulunduğu, diğerlerinin beklemede kaldığı kısmi yürütme durumlarını, üretim gözlem araçlarına erişmeden nasıl tespit edersiniz?
Adaylar genellikle test aracına erişilebilen In-Process Saga takibi veya Saga Denetim Günlükleri ihtiyacını atlar. Çözüm, test konteynerlerinde gRPC veya HTTP çağrılarını katılımcı hizmetlere yönlendiren bir Sidecar deseninin enjekte edilmesini gerektirir; bu, Envoy veya özel proxyler kullanarak gerçekleştirilir. Test aracında her katılımcının durumunu (BEKLEYEN, TAHAHHÜT EDİLEN, İPTAL EDİLEN) izleyen bir Saga Durum Matrisi tutulur. Toxiproxy bir bölüm enjekte ettiğinde, ihmal edilen katılımcıların beklenmedik yan etkiler göstermediğini doğrulamak için bu matrisi sorgulayın. Telafi yollarının yalnızca taahhüt edilen katılımcılar için yürütüldüğünü doğrulamak için Jaeger span etiketlerinde JSONPath doğrulamaları kullanın, böylece kaynakların gerçekten rezerve edilmemiş işlemler için serbest bırakılmaması sağlanır.