Sorunun geçmişi
Monolitik mimarilerde API testi, merkezi oturum depolarında tutulan durumla tek uç noktalar üzerinde basit istek-cevap doğrulamasına dayanıyordu. Mikroservislere geçiş, iş operasyonlarının, senkron ve asenkron zincirler aracılığıyla birden fazla hizmeti kapsadığı dağıtık işlem karmaşıklığı getirdi ve test uzmanlarının hizmet sınırları boyunca durumu takip etmeleri, otomatik ölçekleme ve mavi-yeşil dağıtımlar gibi altyapı dalgalanmalarını göz önünde bulundurmaları gerekti.
Sorun
Geleneksel API otomasyonu, her hizmet çağrısını izole bir işlem olarak değerlendirerek, kısmi hataların hizmet sınırları boyunca telafi edici eylemleri tetiklemesi gereken saga ve dağıtık işlemleri doğrulayamıyor. Ayrıca, sabitlenmiş hizmet uç noktaları, dinamik ölçeklendirmeye karşı testleri kırılgan hale getirirken, kontrol edilen hata enjekte etme eksikliği nedeniyle devre kesici yapılandırmaları ve yeniden deneme politikalarının üretim olayları meydana geldiğinde doğrulanmamasına neden oluyor ve felaket katlanarak devam eden başarısızlıklara yol açıyor.
Çözüm
Dinamik uç noktaların çalışma zamanında çözülmesini sağlayan bir hizmet keşif kaydını (Consul veya Eureka gibi) kullanan bir koreografi-bilinçli test çerçevesi uygulayın. Bu mimari, kısmi başarılarda telafi edici işlemlerin doğru bir şekilde yürütülmesini sağlamak için olay kaynak dinleyicileri aracılığıyla Saga desenini doğrular, hizmet çağrıları boyunca ilişki kimliklerini takip ederek. Ayrıca, uygulama kodunu değiştirmeden veya özel test ortamları gerektirmeden devre kesici doğrulamayı mümkün kılmak için hata enjekte etme işlemlerini destekleyen hizmet ağı kontrol uç noktaları (Istio gibi) ile entegre edin.
public class DistributedSagaTest { private DynamicServiceMesh mesh; private SagaEventValidator validator; private FaultInjector faultInjector; @BeforeMethod public void setup() { mesh = new DynamicServiceMesh(ServiceRegistry.consul()); validator = new SagaEventValidator(KafkaConfig.testConsumer()); faultInjector = new IstioFaultInjector(mesh); } @Test public void testOrderSagaWithCircuitBreaker() { String sagaId = UUID.randomUUID().toString(); OrderRequest order = new OrderRequest("SKU-123", 2); // Aşama 1: Envanteri ayırt Response reserve = mesh.post(Service.INVENTORY, "/reserve", order, sagaId); assertEquals(reserve.getStatus(), 201); // Ödeme hizmetine gecikme enjekte et ve devre kesiciyi tetikle faultInjector.addLatency(Service.PAYMENT, 5000, 0.5); // Aşama 2: Dayanıklılık doğrulaması ile ödemeyi işleyin PaymentResult result = validator.executeWithValidation(sagaId, () -> { return mesh.post(Service.PAYMENT, "/charge", order, sagaId); }); if (result.isCircuitBreakerOpen()) { // Telafi edici işlemin envanteri serbest bıraktığını doğrula validator.awaitCompensatingEvent(sagaId, "INVENTORY_RELEASED", Duration.ofSeconds(5)); InventoryStatus status = mesh.get(Service.INVENTORY, "/status/" + order.getSku(), sagaId); assertEquals(status.getReservedQuantity(), 0); } } }
Bir finansal teknoloji şirketi, işlem doğrulama, dolandırıcılık tespiti, defter yönetimi ve bildirim gönderimi de dahil olmak üzere on iki karşılıklı bağımlı hizmetten oluşan bir mikroservis mimarisine, monolitik bir ödeme işlemcisinden geçiş yaptı. Otomasyon ekibi, başlangıçta bu hizmetleri statik yapılandırılmış uç noktaları içeren geleneksel REST Assured testlerini kullanarak test etmeye çalıştı. Bu durum, Kubernetes podlarının yeniden programlanması nedeniyle hizmet IP adreslerinin ve portlarının öngörülemez bir şekilde değişmesi sonucu ilk hafta içinde test yürütmelerinin yüzde kırkının başarısız olmasına yol açtı.
Ekip, bu istikrarsızlığı çözmek için üç farklı mimari yaklaşımı değerlendirdi. İlk seçenek, tüm hizmetlerin test çalışmaları sırasında bağlanacağı merkezi bir test veritabanı uygulamaktı. Bu, veri tutarlılığını sağlarken dağıtık işlem karmaşıklığını ortadan kaldırdı. Ancak bu, hizmetler arasında tehlikeli bir bağımlılık yarattı ve her hizmetin kendi veri deposunu koruyarak üretim benzeri yapılandırmalara karşı test etme ilkesini ihlal etti; bu, serileştirme hatalarını ve bağlantı havuzuna bağlı sorunları gizleyebilirdi. İkinci yaklaşım, tüm bağımlı hizmetlerin kapsamlı bir şekilde taklit edilmesini, WireMock gibi araçlar kullanarak sağlamak önerildi. Bu, istikrar ve hızlı yürütme sağlasa da, yalnızca gerçek hizmet etkileşimlerinde ortaya çıkan ağ zaman aşımı, devre kesici yapılandırma hataları ve olay aracısı gecikmeleri ile ilgili entegrasyon hatalarını tespit edemedi.
Seçilen çözüm, İstio'yu kullanarak dinamik hizmet keşfini sağlayan bir hizmet ağı yan yana kısa çerçeve uyguladı ve dağıtılmış işlemleri enjekte edilmiş ilişki başlıkları aracılığıyla izleyen özel bir Saga test orkestratörü ile birleştirildi. Bu mimari, testlerin uç noktaları sabit IP'ler yerine ağ keşfi aracılığıyla çözmesini sağladı ve Istio hata enjekte etme yetenekleri, uygulama kodunu değiştirmeden yeniden deneme politikalarının ve devre kesicilerin doğrulanmasını sağladı. Saga orkestratörü, veri tabanında telafi edici işlem olaylarını dinleyen bir olay günlüğü sürdürdü ve kısmi hataların doğru bir şekilde dağıtık defter üzerinde geri dönüş dizilerini tetikleyip tetiklemediğini doğrulamayı mümkün kıldı.
Uygulamanın ardından, çerçeve başarılı bir şekilde her gün yönetilemeyen ortamlarda beş yüz uçtan uca işlem akışını yürüttü ve önceki birim ve sözleşme testlerinin atladığı telafi edici işlem mantığında üç kritik yarış durumu tespit etti. Dinamik keşif mekanizması, çevreye bağlı test hatalarını tamamen ortadan kaldırırken, kaos mühendisliği entegrasyonu, bir sonraki yoğun trafik olayında üretimde kitlesel başarısızlıklara neden olabilecek devre kesici eşiklerinde yapılandırma hatalarını yakaladı ve tahmini on iki saatlik kesinti süresini kurtardı.
Arbitrary sleep gecikmeleri eklemeden dağıtık sistemlerde nihai tutarlılığı nasıl doğruluyorsunuz?
Birçok aday, yürütmeyi önemli ölçüde yavaşlatan ve değişken yük koşullarında güvenilir olmaktan uzak kalan maksimum olası gecikmeye sabitlenmiş Thread.sleep() veya anlamlı beklemeler kullanmayı öneriyor. Doğru yaklaşım, herhangi bir zaman geçmeden iş olaylarının tamamlanmasına dayalı belirleyici çıkış kriterleri ile birlikte, adaptif anketleme uygulamak ve sonlandırmaktır; Awaitility gibi kitaplıklarla birlikte özel durum predikatları kullanarak, veri tabanında veya mesaj aracısında saga tamamlama işaretlerini kontrol eder. Bu, testlerin zamanlama hakkında tahmin yürütmek yerine gerçek tutarlılık sınırını doğrulamasını sağlar ve tutarlılık hizmet seviyeleri hedefleri tarafından tanımlanan kabul edilebilir iş eşiklerine aştığında hızlı bir şekilde başarısız olmasını sağlar.
Kullanıcıdan kaynaklanan sözleşme testi ile uçtan uca entegrasyon testi arasındaki temel mimari fark nedir ve birini diğerinin yerine koymak neden başarısızlığa yol açar?
Adaylar genellikle bu yaklaşımları birbirine karıştırmakta, sözleşme testlerinin tek başına sistem işlevselliğini sağladığını veya uçtan uca testlerin tüm senaryolar için yeterli arayüz doğrulamasını sağladığını önermektedir. Kullanıcıdan kaynaklanan sözleşme testleri, belirli hizmet çiftleri arasındaki şema uyumluluğunu ve istek-cevap sözleşmelerini doğrulamak için Pact gibi araçlar kullanarak, bir sağlayıcıdaki değişikliklerin belirli tüketicileri bozmadığını garanti eder, ancak birden fazla hizmet arasındaki ortaya çıkan davranışları doğrulayamaz. Buna karşılık, uçtan uca testler, bu karmaşık etkileşim örüntülerini ve hata modlarının yayılımını doğrularken, yavaş geri bildirim sağlar ve tüm hizmet sürümü varyasyonlarını test edemez, bu nedenle doğru mimari, arayüz değişiklikleri için hızlı geri bildirim mekanizması olarak sözleşme testlerini, dağıtık işlem sınırlarını hedefleyen seçici uçtan uca senaryolarla destekler.
Birden çok veritabanı ve mesaj aracısını kapsayan dağıtık işlemleri doğrularken test verisi izolasyonunu nasıl ele almalısınız?
Çoğu aday, temizlik betikleri ile paylaşılan test veritabanları veya basit UUID rastgeleleştirmesi öneriyor, oysa mikroservisler ayırıcı veri depolarını tutmaktadır ve tek bir işleme, PostgreSQL, MongoDB ve Kafka konuları üzerinde eşzamanlı olarak kayıtlar oluşturur. Doğru izolasyon, doğrudan veri tabanı temizliğinden ziyade saga telafi mekanizmaları aracılığıyla Star-Wipe deseninin uygulanmasını gerektirir ve testlerin referans tutarlılığını sağlamak için üretimde kullanılan aynı temizlik iş akışlarını çağırmasını sağlar. Ayrıca, testin başlatılması sırasında enjekte edilen dağıtılmış izleme başlıklarını kullanarak oluşturulan tüm verileri etiketlemeniz gerekir, bu da tüm hizmetler arasında yabancı anahtar kısıtlamalarını ve zaman sınırlarını gözeten kesin temizlik sorgularını sağlarken olay kaynaklı ekleme-yalnızca depoları ile zaman sınırına sahip test bağlamlarını dikkate alır.