Monolit ve Microservices: Mimari Seçim Rehberi

## Monolit ve Microservices: İki Uç Değil, Bir Spektrum Mimari seçimi bir inanç meselesi değil, kısıtların çözümüdür. Monolit tek bir dağıtılabilir b...

Monolit ve Microservices: Mimari Seçim Rehberi

Monolit ve Microservices: İki Uç Değil, Bir Spektrum

Mimari seçimi bir inanç meselesi değil, kısıtların çözümüdür. Monolit tek bir dağıtılabilir birimde çalışan uygulamadır; microservices ise her biri bağımsız dağıtılan, ağ üzerinden konuşan küçük servislerdir. İkisinin arasında modüler monolit, "modular monolith", ve birkaç servise ayrılmış ara formlar bulunur. Bu rehber, tercihi sıralı bir değerlendirme akışına oturtmayı amaçlar.

Önkoşul olarak şunları varsayıyorum: HTTP ve REST temelleri, ilişkisel veritabanı bilgisi, konteyner (Docker) kavramı, CI/CD hattı deneyimi. Örnekler dil ve sürümden bağımsızdır; belirli bir framework sürümüne bağlı kod vermiyorum.

Önce Kısıtları Yaz

Mimari tartışmasına girmeden önce ölçülebilir kısıtları belirle:

  • Ekip büyüklüğü ve dağılımı: Kaç kişi, kaç lokasyon, kaç saat dilimi?
  • Dağıtım sıklığı hedefi: Günde bir mi, günde onlarca mı?
  • Trafik profili: Tepe yük, ortalama yük, büyüme beklentisi.
  • Veri tutarlılığı gereksinimi: Anlık tutarlılık mı, eventual consistency kabul mü?
  • Operasyonel olgunluk: Log toplama, izleme, dağıtık izleme (tracing), otomatik dağıtım var mı?
  • Bütçe: Altyapı ve ekip zamanı maliyeti.

Bu liste boşsa mimari tartışması spekülasyona döner.

Karar Ağacı

Aşağıdaki akış katı bir kural değil, düşünme sırasıdır:

  1. Ekip 10 kişinin altında ve tek ürün mü? Modüler monolit ile başla.
  2. Tek dağıtım birimi darboğaz mı? Önce modülerliği artır; servis ayırmayı sonra düşün.
  3. Farklı parçaların ölçeklenme profili çok farklı mı? (örneğin görüntü işleme vs. CRUD API) Ayırma mantıklı olabilir.
  4. Farklı ekipler aynı kod tabanında sürekli çakışıyor mu? Sınır (bounded context) netse servis ayırma gündeme gelir.
  5. Dağıtık sistem operasyonunu yürütecek izleme/log/tracing altyapın var mı? Yoksa önce onu kur.

Bu sorulara "hayır" cevabı çoğu zaman monoliti işaret eder.

Modüler Monolit: Çoğu Projenin Doğru Başlangıcı

Modüler monolit, tek dağıtım birimi içinde net modül sınırları olan uygulamadır. Modüller birbirine doğrudan erişmez; tanımlı arayüzler üzerinden konuşur. Bu disiplin, ileride servis ayırmayı mümkün kılar.

Tipik yapı (dil bağımsız):

app/
  siparis/
    api/         # dışa açılan arayüz
    domain/      # iş kuralları
    infra/       # veritabanı, dış servis adaptörleri
  kullanici/
    api/
    domain/
    infra/
  ortak/

Kurallar:

  • Bir modül diğerinin infra katmanına erişemez.
  • Modüller arası çağrı yalnızca api üzerinden.
  • Veritabanı şeması modül bazında ayrılabilir; ortak tablo erişimi sınırlandırılır.

Bu disiplin korunursa servis ayırma mekanik bir işe dönüşür. Korunmazsa monolit zamanla "büyük toprak yığını" (big ball of mud) haline gelir.

Microservices'in Gerçek Maliyeti

Microservices ücretsiz değildir. Ayırdığın her servis şu yükleri getirir:

  • Ağ gecikmesi ve hata olasılığı: Fonksiyon çağrısı yerine HTTP/gRPC çağrısı; timeout, retry, circuit breaker gerekir.
  • Dağıtık veri: Tek transaction yerine saga veya eventual consistency. Hata durumunda telafi (compensation) mantığı yazılır.
  • Operasyon: Her servis için log, metrik, sağlık kontrolü, sürüm yönetimi.
  • Test: Entegrasyon ve uçtan uca test altyapısı zorunlu hale gelir.
  • Hata ayıklama: Tek stack trace yerine dağıtık izleme gerekir.

Bu maliyetleri karşılayacak ekip ve altyapı yoksa microservices, monolitin sorunlarını çözmek yerine yenilerini ekler.

Sınırları Doğru Çizmek

Servis sınırı, teknik katman değil iş alanı (bounded context) temelli olmalıdır. Yanlış sınır örnekleri:

  • "User service", "Order service", "Payment service" gibi isimler doğru görünse de içleri sürekli birbirine bağımlıysa sınır yanlıştır.
  • Katman bazlı ayırma (örneğin "database service") genellikle anti-pattern'dir; veritabanı paylaşılan bir kaynaktır, servis değil.

Doğru sınırın testi: Bir servisi değiştirdiğinde kaç diğer servisi aynı anda dağıtman gerekiyor? Cevap birden fazlaysa sınır büyük olasılıkla yanlış.

Veri Yönetimi

Monolitte tek veritabanı ve ACID transaction vardır. Microservices'te her servis kendi verisinin sahibidir; başka servisin veritabanına doğrudan bağlanmak yasaktır.

Tutarlılık gerektiğinde:

  • Saga: Adımları ve telafi adımlarını tanımla.
  • Outbox pattern: Veritabanı yazımı ile mesaj yayınını aynı transaction içinde tut, sonra asenkron gönder.
  • Idempotency key: Ağ tekrarlarına karşı istekleri tekilleştir.

Bu kalıplar monolit içinde de uygulanabilir; servis ayırmadan önce öğrenmek maliyeti düşürür.

Güvenlik Etkileri

  • Yüzey artışı: Her servis yeni bir ağ uç noktasıdır. Servisler arası kimlik doğrulama (mTLS, token) gerekir.
  • Yetkilendirme: Monolitte tek noktada yapılan kontrol, servislerde dağıtık hale gelir; tutarlı politika yönetimi şart.
  • Sır yönetimi: Servis başına kimlik bilgisi; merkezi sır yönetimi (vault) ihtiyacı doğar.
  • Ağ segmentasyonu: Servisler arası trafik kısıtlanmalı; varsayılan "herkes herkese" yaklaşımı risklidir.
  • Girdi doğrulama: Her servis kendi girdisini doğrulamalı; "üst katman doğruladı" varsayımı yanlıştır.

Monolitte de bu başlıklar geçerlidir; ancak servis ağı büyüdükçe yönetim yükü katlanır.

Yaygın Hatalar

  • Erken ayırma: Ekip küçükken servis sayısını artırmak, teslim hızını düşürür.
  • Paylaşılan veritabanı: Servisler aynı şemayı paylaşırsa bağımsız dağıtım imkânsız hale gelir.
  • Senkron zincir: Servis A, B'yi; B, C'yi senkron çağırıyorsa tek hata tüm zinciri durdurur.
  • Ortak kütüphane bağımlılığı: Paylaşılan kütüphanede yapılan kırıcı değişiklik tüm servisleri etkiler; sürümleme disiplini gerekir.
  • İzleme olmadan ayırma: Dağıtık izleme yoksa hata ayıklama süresi katlanır.
  • "Microservice = küçük kod" sanmak: Ölçüt satır sayısı değil, bağımsız dağıtılabilirlik ve sahipliktir.

Geçiş Stratejisi

Monolitten servislere geçiş kademeli olmalı:

  1. Modül sınırlarını netleştir; modüller arası erişimi arayüzlere indir.
  2. En bağımsız modülü seç; önce onu ayrı bir süreç olarak çalıştır, aynı veritabanına bağlı kalsın.
  3. Trafiği yavaşça yeni sürece kaydır (strangler fig).
  4. Veri sahipliğini ayır; şema bölünmesini planla.
  5. İzleme, log ve dağıtık izlemeyi bu servis için kur.
  6. Aynı döngüyü bir sonraki modül için tekrarla.

Bu sıralama, geri dönüşü mümkün kılar; her adım tek başına değerlendirilebilir.

Karar Kontrol Listesi

Servis ayırmadan önce şu sorulara yazılı cevap ver:

  • Bu servisi tek başına dağıtabiliyor muyum?
  • Kendi verisinin tek sahibi mi?
  • Diğer servislerle sözleşmesi (API) sürümlenmiş mi?
  • Hata durumunda davranışı tanımlı mı (timeout, retry, fallback)?
  • İzleme ve alarmı var mı?
  • Ekibin bu servisi sahiplenecek bir sorumlusu var mı?

Cevaplardan biri "hayır" ise ayırma kararını ertelemek genellikle daha ucuzdur.

Sonuç

Monolit ve microservices birbirinin alternatifi değil, aynı spektrumun iki ucudur. Çoğu proje için doğru başlangıç, net modül sınırlarına sahip bir monolittir. Servis ayırma, ölçülebilir bir kısıt (ekip ölçeği, dağıtım sıklığı, ölçeklenme profili farkı) ortaya çıktığında ve operasyonel altyapı hazır olduğunda gündeme gelir. Kararı mimari moda değil, kısıtlara ve ölçülebilir hedeflere dayandır.

İLGİLİ İÇERİKLER

Bunları da Okumak İsteyebilirsiniz