Modular Monolith’ten Microservices’e Ne Zaman Geçilmeli? (Gerçek Sinyaller vs Yanlış Sebepler)

Modular Monolith’ten Microservices’e Ne Zaman Geçilmeli? (Gerçek Sinyaller vs Yanlış Sebepler) konusunu anlatan renkli 3D teknik illüstrasyon

Microservices’e geçiş, mevcut deployment ve veri sınırlarını değiştiren bir karardır. Codebase büyüdüğünde veya bir release yavaşladığında ilk çözüm olarak servisleri ayırmak kolay görünür. Fakat ihtiyaç belirsizse network, veri tutarlılığı ve operasyon maliyetini artırıp aynı coupling’i başka bir yere taşıyabiliriz.

Tercihim, Modular Monolith içinde sınırları netleştirip ayrı deployment’ın sağlayacağı kazancı ölçerek ilerlemek. Bu tercih, belirli bir modülde bağımsız kapasite, failure isolation veya release ihtiyacı belirginleştiğinde değişir.

Microservices’e geçiş için yeterli olmayan sinyaller

“Sistem büyüyor”, “codebase karmaşık” veya “büyük şirketler böyle yapıyor” tek başına karar gerekçesi değildir. Karmaşık kodu ayrı process’lere taşımak domain ve dependency sorunlarını çözmez; hatayı izlemek için daha fazla bileşeni takip etmeyi gerektirebilir.

Deployment’ın yavaşlaması ise araştırılması gereken gerçek bir belirti olabilir. Sorun pipeline, test süresi veya manual approval adımlarındaysa mimariyi parçalamak kök nedeni değiştirmez. Sık değişen bir modül bütün release’i bloke ediyorsa ve contract’ını bağımsız tutabiliyorsanız servis ayrımının gerekçesi güçlenir.

Microservices yalnız organizasyonel bir çözüm değildir. Takım ownership’i yanında farklı yük profili, teknoloji ihtiyacı ve failure isolation da rol oynayabilir. Ancak process ayırmak bu faydaları otomatik sağlamaz. Microsoft’un Microservices mimari değerlendirmesi faydaları ve ek maliyetleri birlikte ele alıyor.

Bağımsız kapasite ve deployment ihtiyacı

Horizontal scaling gerektiğinde Microservices zorunlu değildir; uygun state yönetimiyle monolith’i de birden fazla instance üzerinde çalıştırabilirsiniz. Asıl soru, bütün sistemi büyütmek yerine tek bir capability’yi ölçeklemenin kaynak ve operasyon açısından anlamlı bir fark oluşturup oluşturmadığıdır.

Örneğin yoğun bir raporlama veya arka plan işinin yükünü ayrı worker’a taşımak yeterli olabilir. Bu ihtiyacı doğrudan yeni bir service/database sayısına çevirmeyin. Önce aynı yük altında CPU, memory, throughput, gecikme ve maliyeti karşılaştırın.

Ayrı ekipler aynı codebase üzerinde verimli çalışabilir. Servis ayrımı; ekiplerin birbirini bekleyen release’lerini, uyumsuz lifecycle ihtiyaçlarını veya ayrı SLO’larını çözüyorsa değer kazanır. Servislerin yine birlikte deploy edilmesi gerekiyorsa bağımsızlık hedefini henüz karşılamamış olabilirsiniz.

Microservices’e geçiş öncesi boundary ve operasyon

Bir modülü ayırmadan önce iş sorumluluğunu, yazdığı verinin sahipliğini ve diğer modüllerle hangi contract üzerinden konuştuğunu belirleyin. Sık birlikte değişen ve çok sayıda senkron çağrı yapan iki parçayı ayırmak, deployment sayısını artırırken coupling’i koruyabilir.

Microservices’e geçiş kararında ekip sayısı için evrensel bir “5–6 kişi altındaysa geçme” eşiği yoktur. Küçük ekip için operasyon maliyeti daha ağır hissedilebilir; fakat managed platform ve deneyim bu dengeyi değiştirebilir. Deployment automation, tracing, alarm, rollback ve olay müdahalesi sorumlulukları hazır değilse önce bu eksikleri giderin.

Failure isolation da yalnız ayrı process ile bitmez. Paylaşılan database, sınırsız request kuyruğu veya ardışık senkron çağrılar hatayı yayabilir. Timeout ve kaynak sınırlarını bağımlılık yolunda tasarlayın. Bulkhead pattern’i izolasyonun kaynak bütçeleriyle ilişkisini açıklıyor.

Microservices’e geçişi adım adım yürütmek

İlk aday yalnız en az dependency’si olan modül olmamalı. Ayrımın business faydasını, veri taşıma maliyetini ve operasyon riskini birlikte değerlendirin. Küçük bir extraction’ın release veya kapasite sorununu gerçekten çözüp çözmediğini görmek, geniş bir migration’dan daha iyi geri bildirim verebilir.

  1. Mevcut boundary ve data ownership ilişkilerini çıkarın. Kalacak ve taşınacak sorumlulukları belirleyin.
  2. API/event contract’ını ve geriye uyumluluk kurallarını tanımlayın. Private database modelini dış contract olarak kullanmayın.
  3. Backfill, devam eden yazılar, cutover ve rollback sırasında verinin hangi tarafta authoritative olduğunu belirleyin. Plansız dual write tutarsızlık oluşturabilir.
  4. Aynı trafik/veri profiliyle release süresi, hata oranı, P95/P99 gecikme ve operasyon yükünü karşılaştırın. Fayda yoksa extraction’ı genişletmeyin.

İşlem birden fazla service/database’e yayılıyorsa local transaction varsayımı değişir. Retry, idempotency ve gerekiyorsa compensation davranışını açıkça tasarlayın; eski atomiklik ihtiyacını yalnız endpoint’leri ayırarak koruyamazsınız.

Strangler Fig ne sağlar?

Strangler Fig, çağrıların bir bölümünü yeni implementasyona yönlendirirken eski sistemin çalışmasını sürdürmeyi sağlar. Uygun interception/routing noktası varsa migration riskini aşamalara bölebilirsiniz. Bununla birlikte her sistemde en güvenli veya tek doğru yol değildir; façade/routing katmanı da latency ve failure point yaratabilir.

Yeni ve eski akışların aynı veriyi nasıl yöneteceğini, fallback’in hangi state’te güvenli olduğunu ve eski parçayı ne zaman kaldıracağınızı planlayın. Strangler Fig dokümantasyonu pattern’in uygunluk ve sınırlarını gösteriyor.

Kısa vaka: Deployment ayrıldı, coupling kaldı

Bir projede erken Microservices geçişiyle servisler ve deployment’lar ayrıldı. Ancak servisler arası bağımlılık arttı, latency yükseldi ve debugging zorlaştı. Ayrı deployment tek başına sistemin daha bağımsız veya dayanıklı olmasını sağlamadı.

Bu nedenle kararın sonucunu service sayısıyla ölçmeyin. Modular Monolith’te domain boundary’leri netleştirmek ve belirli bir ihtiyacı ölçmek, parçalamanın gerekli olup olmadığını daha iyi gösterir.

By tanju.bozok

Senior .NET Engineer | Backend architecture, distributed systems & real-time communication