Finansal teknoloji ve envanter yönetim sistemlerinde, paylaşılan verilere eşzamanlı erişim, standart işlevsel testlerin sağladığından daha sıkı tutarlılık garantileri gerektirir. ACID özellikleri, özellikle İzolasyon, çift harcama veya aşırı satış gibi yarış koşullarını önler, ancak çoğu otomasyon seti testleri ardışık olarak yürütür, bu da ince eşzamanlılık hatalarını maskelemektedir. Bu soru, Read Committed izolasyonu kullanan uygulamaların, yük altında üretimde başarısız olmasına neden olan üretim olaylarından ortaya çıkmıştır; bu durum da defter bakiyelerini bozan yazma kayması anormalliklerine izin vermektedir. Geleneksel QA yaklaşımları, belirsiz, yavaş testler yaratan Thread.sleep() çözümlerine dayanıyordu; bu da Serileştirilebilir izolasyon seviyeleri için belirleyici bir doğrulama stratejisi gerektiriyordu.
Serileştirilebilir izolasyonu doğrulamak, anormallikleri açığa çıkarmak için hassas zamanlamayla birden fazla işlemi koordine etmeyi gerektirir; bu anomaliler arasında yazma kayması (eşzamanlı işlemler üst üste binen verileri okur ve bu anlık görüntüye dayalı olarak ayrı veri kümelerini günceller) ve hayalet okumalar (bir aralık sorgusu tekrar yürütüldüğünde eşzamanlı eklemeler nedeniyle farklı sonuçlar döner) bulunmaktadır. Standart test çerçeveleri senaryoları ardışık olarak yürütür ve bu kenar durumlarını tamamen gözden kaçırır, basit eşzamanlı yürütme ise belirleyici olmayan, belirsiz hatalar üretir; bu da CI/CD güvenini zedeler. Yapay gecikmeler yanlış olumlu sonuçlar yaratır ve yürütme hızını düşürürken, dağıtılmış PostgreSQL kümeleri, replikasyon gecikmesi ve saat çarpıklığı gibi karmaşıklıklar ekler. Zorluk, veritabanının anormal dizileri doğru bir şekilde ne zaman engellediğini veya durdurduğunu doğrulamak için belirleyici olarak belirli işlem birbirliklerini zorlayabilen yeniden üretilebilir testler oluşturmaktır.
Açık Happens-Before grafik doğrulaması ve CountDownLatch veya Phaser gibi bariyer senkronizasyon mekanizmaları kullanarak belirleyici bir eşzamanlılık test kiti uygulayın. PostgreSQL'in pg_stat_activity ve pg_locks sistem görünümlerini gerçek zamanlı işlem durumlarını izlemek için kullanın ve yürütme geçmişinin doğruluğunu doğrulamak için Jepsen-tarzı düzleştirme kontrolü gerçekleştirin. Yazma kayması tespiti için, iki eşzamanlı işlemin üst üste binen anlık görüntüleri okuduğu ve çelişkili yazmalar denediği testler oluşturun; bir işlemin bozulduğunu, serileştirme hatası (SQLSTATE 40001) ile abort edildiğini doğrulayın veya bozulmuş verileri kaydetmemesini sağlayın. Doğru ihtilafta yönetimi göstermek için danışmanlık kilitleri veya SELECT FOR UPDATE desenlerini kullanın ve tutarlılığı pg_dump anlık görüntüleri ve belirleyici tekrar yürütme ile doğrulayın.
Bir finansal defter sisteminde, paylaşılan hesaplar arasında eşzamanlı bakiye transferleri yapılmaktadır; negatif bakiyeler için kritik iş kuralı bulunmaktadır. Bir Siyah Cuma yük testi simülasyonu sırasında, iki otomasyon ipliği aynı anda Hesap A'dan B'ye ve Hesap B'den C'ye transferler gerçekleştirerek, her iki işlemin de olumlu bakiyeleri okuduğu klasik bir yazma kayması senaryosu yaratır; ancak bunların birleşik etkisi kısıtlamaları ihlal eder.
Çözüm A: Thread.sleep() tabanlı koordinasyon İşlem adımları arasında sabit gecikmeler ekleyerek yarış koşullarını simüle etmek için standart Java Thread.sleep() çağrılarını kullanın; yürütmeyi kritik bölümlerde duraklatın. Artılar: Temel JUnit veya TestNG bilgisi ile uygulaması son derece basit; ek kütüphaneler gerektirmez. Eksiler: Belirleyici olmayan ve belirsiz; yarış koşulları daha hızlı CI donanımında tezahür etmeyebilir veya daha yavaş çalışanlarda yanlış bir şekilde başarısız olabilir. Test süresini kat kat arttırarak CI/CD hattı verimliliğini mahveder ve yanlış olumlu sonuçların alarm yorgunluğu yaratmasını sağlar.
Çözüm B: Veritabanı seviyesinde kilitleme ile NOWAIT
PostgreSQL'in sorgulardaki NOWAIT seçeneğini kullanarak, kilit rekabeti sırasında derhal başarısızlığı zorlamak için testleri try-catch blokları içinde sarın. Artılar: Özel senkronizasyon mantığı olmadan yerel veritabanı hata işlemesini kullanır; en fazla rekabet mevcut olduğunda hızlı bir şekilde yürütülür. Eksiler: Gerçekten Serileştirilebilir izolasyon davranışını doğrulamaz - yalnızca kilit edinme zamanlamasını doğrular. Hayalet okuma senaryolarını tamamen gözden kaçırır ve yazma kayması tespitinde yanıltıcı bir güven sağlar.
Çözüm C: İşlem sıralaması ile belirleyici eşzamanlılık kiti
Java'nın Phaser bariyerlerini kullanarak belirli SQL işlem sınırlarında iş parçacığı yürütmesini senkronize eden bir TransactionCoordinator sınıfı oluşturun. Artılar: Anormalliklerin belirleyici tespitine sahip yeniden üretilebilir test senaryoları; rastgele beklemeler olmadan hızlı yürütme. QuickTheories gibi çerçevelerle, belirsizliği korurken çeşitli birbirlik takvimleri oluşturma özelliği sunarak, mülk tabanlı testleri mümkün kılar. Eksiler: Daha yüksek başlangıç mühendislik maliyeti ve işlem yaşam döngüsü durumları ile iş parçacığı senkronizasyon primitiflerine derin bir anlayış gerektirir.
Seçilen çözüm ve sebebi:
Çözüm C'yi seçtik çünkü finansal uyum testlerinde tutarsızlık kabul edilemez ve Çözüm A, üç önceki sürümde kritik bir hatayı yakalayamamıştı. TransactionCoordinator'ı CyclicBarrier kullanarak, yazma kayması yaratan tam etkileşimi zorlamak için uyguladık: her iki işlem de bakiyeyi okur, her ikisi de kısıtlamaları doğrular, her ikisi de yazmayı dener ve PostgreSQL'in ikinci taahhütü SQLSTATE 40001 ile iptal ettiğini varsayıyoruz. Bu yaklaşım, olasılık beklemesi olmadan belirli bir açık pencere test etmemizi sağladı.
Sonuç: Çerçeve hemen uygulamanın tekrar deneme mantığının serileştirme hatalarını yuttuğunu ve bunları genel veritabanı hataları olarak muamele ettiğini, bu durumun üretimde sonsuz döngülere yol açtığını tespit etti. Tekrar mekanizmasını, SQLSTATE 40001'i özellikle yakalayıp üstel geri dönüşle tekrar denemesi için düzelttikten sonra, testler tutarlı bir şekilde geçmeye başladı. Thread.sleep() yaklaşımına göre test seti yürütme süresi %80 azaldı ve 10.000 Jenkins CI yürütmesi boyunca sıfır yanlış olumlu sonuç elde edildi; sonuç olarak, bakiye tutarsızlıklarından dolayı potansiyel $2 milyon gelir kaybını önledik.
PostgreSQL, Serileştirilebilir izolasyonu Snapshot İzolasyonundan nasıl farklı bir şekilde uyguluyor ve bu, otomasyon testleri için neden önemlidir?
PostgreSQL, katı iki aşamalı kilitleme yerine optimistik bir eşzamanlılık kontrol mekanizması olan Serileştirilebilir Anlık İzolasyonu (SSI) kullanır. SSI, eşzamanlı işlemler arasındaki okuma-yazma bağımlılıklarını takip eder ve serileştirme anormalliklerine yol açabilecek işlemleri iptal eder; oysa Anlık İzolasyon (kullanılan Tekrar Edilebilir Okuma) yalnızca yazma-yazma çelişkilerini tespit eder ve yazma kayması olmasına izin verir. Otomasyon testi için bu, testlerin serileştirme_hatası istisnalarını (SQLSTATE 40001) beklemesi ve bunları istenen, doğru davranış olarak işlemesi gerektiği anlamına gelir; bu durum kaç adayın yanlışlıkla Serileştirilebilir in tüm eşzamanlılıkları kilitleyerek önlediğini veya bunların önceden ilerlemeyi garantilediğini varsaydıklarını gözden kaçırmaktadır. Bu, meşru serileştirme çelişkileri meydana geldiğinde, testlerin başarısız olduğu veya bloke etme ile iptal etme davranışları arasındaki ayrımı kaçırdığı anlamına geliyor.
Belirleyici eşzamanlılık testleri, izolasyon seviyelerini doğrulamak için neden stres testleri veya olasılıksal yöntemlerden üstündür?
Stres testleri, yarışı tetiklemek için olasılığa ve donanım zamanlamasına dayanır; bu da belirleyici olmayan ve doğası gereği belirsizdir - bu, CI/CD hattı güveni için bir ölüm çanı gibidir. Belirleyici test, belirli işlemlerin belirleyici olan belirli birbirliklerini zorlamak için açık senkronizasyon bariyerleri (örneğin CountDownLatch veya CompletableFuture) kullanarak, yazma kayması ve hayalet okuma senaryolarının her bir yürütmede test edilmesini sağlar; bu, CPU hızına veya yüke bakılmaksızın gerçekleşir. Bu yaklaşım, eşzamanlı testi olasılıklıdan belirleyici hale getirerek, hataların hassas bir şekilde yeniden üretilmesini sağlar ve belirli çelişki pencerelerine yönelik hedefleme yoluyla yürütme zamanını azaltır. Adaylar genellikle belirleyici testlerin daha hızlı çalıştığını ve olasılıksal testlerin sağlayamayacağı hata ayıklama bilgilerini sunduğunu gözden kaçırmaktadır; bu bilgiler, başarısızlığa yol açan tam işlem dizilerini içerir.
Serileştirilebilir bir işlemin bir hayalet okumayı gerçekten önlediğini, zamanlama şansına dayanan satır sayısı onaylarına güvenmeden nasıl doğrularsınız?
Hayalet okumalar, bir işlem bir aralık sorgusunu tekrar yürüttüğünde ve başka bir işlem tarafından eşzamanlı olarak eklenen yeni kayıtlar nedeniyle farklı sonuçlar aldığı durumdur. Önlemeyi belirleyici olarak doğrulamak için, üç koordine iş parçacığı ile bir test oluşturun: T1 bir işlem başlatır ve SELECT * FROM orders WHERE amount > 100 sorgusunu çalıştırır (5 satırı yakalar), T2 yeni bir kayıt ekler ve taahhüt eder, ve T3 bariyerler aracılığıyla koordinasyonu sağlar. Daha sonra T1, aynı işlem içinde aynı sorguyu tekrar yürütür. Gerçek Serileştirilebilir izolasyonda, PostgreSQL sonuçların 5 satırı koruyacağına (hayalet engellenir) veya T1'in bir serileştirme hatası ile iptal edileceğine garanti verir. Test onayı, satır sayısının sabit kaldığını veya işlemin beklenen SQLSTATE 40001 istisnasını atıp atmadığını kontrol etmelidir. Adaylar genellikle PostgreSQL'de Serileştirilebilir durumunun bloke etmek yerine iptal edebileceğini gözden kaçırır ve onaylarında her iki geçerli sonucu da yeterince ele almazlar veya zamanlama kontrolü yapmadan COUNT(*) onayları kullanarak hatalı bir yaklaşım sergilerler.