Veritabanı şeması değişiklikleri, yazılım dağıtımının en korkulan yönü olmuştur ve genellikle bakım pencereleri ve manuel doğrulama betikleri gerektirmiştir. Kuruluşlar mikro hizmetleri ve sürekli dağıtım uygulamalarını benimsemeye başladıkça, şema değişikliklerinin sıklığı dramatik bir şekilde artmış ve manuel doğrulama pratik hale gelmemiştir. Kesintisiz dağıtım modellerinin ortaya çıkışı, şemaların birden fazla sürüm arasında geçmişe dönük uyumluluğu korumasını gerektirmiştir, bu da otomatik doğrulama ihtiyacını doğurmuştur; böylece kırıcı değişiklikler üretim ortamına ulaşmadan tespit edilebilir.
Temel zorluk, yeni bir şema göçünün veritabanı ile bununla erişim sağlayabilecek birden fazla hizmet sürümü arasındaki örtük sözleşmeyi ihlal etmediğini doğrulamaktır. Geleneksel test uygulama kodunu statik bir şemaya karşı doğrular, ancak Sürüm N+1’in yazdığı verilerin Sürüm N tarafından okunamadığı veya sütun adlarının değiştirilmesinin geçiş penceresi sırasında mevcut sorguları bozabileceği senaryoları tespit edemez. Ayrıca, geri alma prosedürleri nadiren otomatik olarak test edilir, bu da ekiplerin, en çok ihtiyaç duyulduğunda başarısız olabilecek doğrulanmamış kurtarma yollarıyla baş başa kalmasına neden olur ve bu da uzatılmış kesintilere ve veri bozulması risklerine yol açar.
Sağlam bir doğrulama hattı, geçici veritabanı kopyaları ve sözleşme test ilkelerini kullanarak üç aşamalı bir kapama mekanizması uygular. İlk olarak, göç, üretim benzeri verilerle doldurulmuş bir TestContainers örneğine uygulanır ve çalışma zamanı hatalarını ve performans düşüşünü tespit etmek için kullanılır. İkinci olarak, geçmişe dönük uyumluluk sağlar ve önceki hizmet sürümünün entegrasyon test suite’ini yeni şemaya karşı çalıştırarak, eski kod yollarının hala geçerli verileri okuyup yazabileceğini garanti eder. Üçüncü olarak, göç edilen şemaya karşı otomatik geri alma betikleri çalıştırılır, böylece geri alma yolunun veritabanını veri kaybı olmadan tutarlı bir duruma döndürdüğünü doğrular ve tablo satır sayıları ile kritik alan bütünlüğü için kontrol topları kullanır.
@Test public void testSchemaMigrationBackwardCompatibility() { // Aşama 1: Göçü taze konteynere uygula DatabaseContainer oldDb = new DatabaseContainer("postgres:13"); oldDb.start(); Flyway.configure().dataSource(oldDb.getJdbcUrl(), "user", "pass") .target("V1__baseline").load().migrate(); // Eski şemayı kullanarak veri ekle User legacyUser = oldDb.insertUser("legacy@example.com"); // Aşama 2: Yeni göçü uygula Flyway.configure().dataSource(oldDb.getJdbcUrl(), "user", "pass") .load().migrate(); // V2__add_profile'a göç eder // Aşama 3: Eski hizmetin hala okuyup yazabildiğini doğrula LegacyUserService oldService = new LegacyUserService(oldDb.getDataSource()); User fetched = oldService.findById(legacyUser.getId()); assertNotNull("Eski hizmet mevcut kullanıcıları okumalıdır", fetched); // Aşama 4: Geri alma bütünlüğünü doğrula Flyway.configure().dataSource(oldDb.getJdbcUrl(), "user", "pass") .target("V1__baseline").load().migrate(); // Geri alma int countAfterRollback = oldDb.countUsers(); assertEquals("Geri alma veri sayısını korumalıdır", 1, countAfterRollback); }
Bir fintech şirketi, görünüşte basit bir göçün "account_balance" sütununu "balance" olarak yeniden adlandırmasının ardından üç saatlik ciddi bir kesintiyle karşılaştı. Dağıtım, yeni kodu çalıştıran örneklerin yeniden adlandırılmış sütuna yazdığı ve hala eski sütun adını okumaya çalışan örneklerin bulunduğu bir sürüm güncelleme stratejisi ile gerçekleştirildi. Bu uyumsuzluk, işlem hataları ve veri bozulmasını tetikleyen olaylar zincirini başlattı ve bu durum manuel müdahale gerektirdi.
Ekip, tekrarı önlemek için üç ayrı yaklaşım üzerine düşündü: her göç için manuel QA kontrol listeleri uygulamak, veritabanı kopyalama ile mavi-yeşil dağıtımlar benimsemek veya otomatik bir doğrulama hattı inşa etmek. Manuel kontrol listeleri insan hatası potansiyeli ve ekip büyüdükçe ölçekleme sınırlamaları nedeniyle reddedildi. Mavi-yeşil dağıtımlar, veri hacimleri için çok maliyetli olarak değerlendirildi ve çift depolama kapasitesi ve karmaşık çoğaltma gecikmesi yönetimi gerektirdiği için kendi risklerini getirdi.
Sonuç olarak, otomatik bir hattı TestContainers ve Flyway geri çağrıları kullanarak uygulamayı seçtiler ve bu her göçü önceki iki uygulama sürümüne karşı doğruladı. Bu çözüm, önceki API sürümüne hala atıfta bulunan bir sütunu düşürme girişimini tespit etti ve otomatik olarak birleştirme isteğini üretime ulaşmadan önce engelledi. Sonuç olarak, göçle ilgili olaylarda %90 azalma sağlandı ve şema değişikliklerini bakım pencereleri gerektirmeden 50 kat daha sık dağıtma yeteneği kazandılar.
Veritabanı göçlerinde geçmişe dönük uyumluluğu test etmenin yeterli olmadığının nedeni nedir?
Birçok aday, eski kodun yeni şemalarla çalıştığını sağlamaya odaklanır ancak yeni kodun da geçiş sürecinde eski kodun yazdığı verileri işleyebilmesi gerektiğini ihmal eder. İleriye dönük uyumluluk hataları, yeni şemanın varsayılanları olmayan NOT NULL sütunları gibi kısıtlamalar getirdiğinde ortaya çıkar ve bu da yeni uygulama sürümünün eski kayıtlarla karşılaştığında çökmesine neden olur. Çözüm, yeni sütunların bir sürümde nullable veya varsayılan değerlerle eklenmesi, ardından tüm örnekler göç ettikten sonra kısıtlanması gereken genişletme-sözleşme desenlerinin uygulanmasını gerektirir.
Göç doğrulama testlerinizde işlem izolasyon düzeyi seçiminiz, üretimde oluşacak yarış koşullarını nasıl gizleyebilir?
Adaylar sıklıkla test veritabanlarında üretim yapılandırmalarından farklı olan varsayılan izolasyon düzeylerini kullanır, bu da eşzamanlılık testlerindeki yanlış pozitiflere yol açar. Eğer üretim READ COMMITTED kullanıyorsa, ancak testler SERIALIZABLE kullanıyorsa, testler, gerçek yük altında tablo kilitlerine neden olan atomik olmayan DDL işlemleri içeren göç betikleri ile geçmesine rağmen başarılı olabilir. Ayrıntılı çözüm, test konteynırlarını üretim izolasyon düzeylerini yansıtacak şekilde yapılandırmayı ve göçleri simüle edilmiş trafik okuma ve yazma işlemleri ile uygulayan eşzamanlı yürütme simülasyonları yapmayı gerektirir; özellikle ölü kilitler ve kilit zaman aşımına karşı kontrol edilmektedir.
Geri alma betiğini test etme ile uygulama sürümleri arasındaki düşürme uyumluluğunu test etme arasındaki temel fark nedir?
Bu ayrım, Flyway'in geri alma işleminin hatasız çalıştığını varsayan birçok mühendis tarafından karıştırılmaktadır. Ancak, başarılı bir veritabanı geri alımı, önceki uygulama sürümünün geri alınan veri durumunu doğru bir şekilde yorumlayabileceğini garanti etmez. Yeni sürüm, işlem sırasında verileri dönüştürüyorsa, önceki sürüm geri alımdan sonra beklenmeyen null veya formatlarla karşılaşabilir ve bu da çalışma zamanı istisnalarına neden olabilir. Çözüm, uygulamanın yükseltildiği, veri dönüşümlerini işlediği, ardından veritabanının geri alındığı ve önceki uygulama sürümünün geri getirilmesiyle doğrulandığı entegrasyon testlerini gerektirir.