Mikroservis ve Monolitik Farkı Nedir

Yazılım mimarisinde mikroservis (Microservices) ve monolitik yapı nedir, farkları nelerdir? Bağımsız dağıtım, veritabanı izolasyonu ve ölçeklenebilirlik.

Yozel

15 dakika

Mikroservis ve Monolitik Farkı Nedir
İçindekiler (21)

Modern yazılım mühendisliği dünyasında bir kurumsal uygulamanın, yüksek trafikli bir finans platformunun veya küresel ölçekli bir dijital ürünün temelini atarken verilen en kritik mühendislik kararı, sistemin mimari topolojisidir. Geliştirici ekiplerin yıllardır tartıştığı mikroservis ve monolitik mimari farkı, yalnızca kodun klasörlere nasıl ayrıldığıyla ilgili teknik bir tercih değil; organizasyonel çeviklik, hata izolasyonu, dağıtım sıklığı, veri tutarlılığı ve bulut altyapı maliyetlerini doğrudan belirleyen stratejik bir yol haritasıdır. Uygulama ve yazılım ekosisteminde doğru zamanda doğru mimari deseni seçmek, bir girişimin hızla pazara çıkması ile teknik borç batağında boğulması arasındaki ince çizgiyi oluşturur. Bu kapsamlı mimari rehberde; klasik monolitik yapılardan modüler monolite (Modular Monolith), dağıtık mikroservis ekosistemlerinden veritabanı izolasyonuna (Database-per-Service), Transactional Outbox deseninden Saga Pattern ile dağıtık işlem yönetimine kadar tüm teknik detayları derinlemesine inceliyoruz.

Monolitik Mimari (Monolithic Architecture) Nedir ve Nasıl Çalışır?

Monolitik mimari, bir yazılım sisteminin tüm fonksiyonel bileşenlerinin —kullanıcı arayüzü katmanı (veya API ağ geçidi), iş mantığı modülleri (sipariş, ödeme, stok, kimlik doğrulama, faturalama, bildirim) ve veri erişim katmanının— tek bir kod tabanında (codebase) birleştirildiği, birlikte derlendiği ve tek bir çalıştırılabilir paket (single deployable artifact; örneğin tek bir JAR, WAR, Binary veya Docker imajı) olarak sunucuya dağıtıldığı geleneksel tasarım yaklaşımıdır. Monolitik bir uygulamada tüm modüller aynı işletim sistemi sürecini (process), aynı bellek alanını (memory space / heap) ve neredeyse her zaman tek bir merkezi ilişkisel veritabanını paylaşır.

Geleneksel üç katmanlı (Three-Tier) veya temiz mimari (Clean / Hexagonal Architecture) ile kurgulanan bir monolitik yapıda istemciden gelen bir HTTP isteği; sunum katmanı (Presentation / Controller Layer) tarafından karşılanır, iş katmanı (Business Logic / Application Service Layer) içindeki sınıflar ve fonksiyonlar arasında doğrudan bellek içi (in-memory) metot çağrılarıyla işlenir ve veri erişim katmanı (Data Access / Repository Layer) üzerinden merkezi SQL veritabanına kaydedilir. Modüller arası iletişimde ağ gecikmesi (network latency), serileştirme (serialization/deserialization) maliyeti veya paket kaybı gibi dağıtık sistem problemleri yaşanmaz.

Monolitik Mimarinin Güçlü Yönleri ve Mühendislik Avantajları

  • Geliştirme ve İlk Kurulum Basitliği (Low Cognitive Load): Tek bir IDE projesi, tek bir paket yöneticisi ve tek bir derleme süreci (build pipeline) bulunur. Yeni başlayan projelerde (MVP) ve küçük mühendislik ekiplerinde geliştirme hızı son derece yüksektir; bilişsel yük (cognitive load) minimum seviyededir.
  • Sıfıra Yakın Modüller Arası İletişim Gecikmesi: Sipariş modülünün stok modülünü veya kampanya hesaplama motorunu çağırması, aynı işlemci belleği içerisindeki bir fonksiyon çağrısından (in-process function call) ibarettir; nanosaniyeler sürer ve ağ protokolü yükü oluşturmaz.
  • ACID İşlem Bütünlüğü (Transactional Integrity): Tüm tablolar aynı veritabanı şemasında yer aldığı için sipariş oluşturma, müşteri bakiyesini düşme, kupon kullanımını işaretleme ve stok güncelleme adımları tek bir BEGIN TRANSACTION ... COMMIT / ROLLBACK bloğu içinde %100 atomik olarak yürütülebilir. Herhangi bir adımda hata çıkarsa veritabanı motoru tüm değişiklikleri milisaniyeler içinde geri alır.
  • Kolay Hata Ayıklama ve Uçtan Uca Test (End-to-End Testing): Tüm uygulama tek bir süreçte çalıştığından, yerel geliştirme ortamında (localhost) tüm sistemi ayağa kaldırıp adım adım (step-by-step) breakpoint koyarak hata ayıklamak ve entegrasyon testlerini koşmak son derece pratiktir.
  • Düşük Altyapı ve Operasyon Maliyeti: Karmaşık servis keşif (Service Discovery) araçlarına, dağıtık izleme (Distributed Tracing) altyapılarına veya mesaj kuyruklarına ilk aşamada ihtiyaç duyulmaz; bir yük dengeleyici (Load Balancer) arkasında birden fazla monolit kopyası çalıştırmak çoğu orta ölçekli iş yükü için yeterlidir.

Monolitik Mimarinin Darboğazları: "Big Ball of Mud" Sendromu

Proje büyüdükçe, kod satırı sayısı yüz binleri aştıkça ve aynı kod tabanında çalışan yazılım geliştirici sayısı 25-30 kişiden fazlalaştıkça monolitik yapı kendi ağırlığı altında ezilmeye başlar. Sınırları net çizilmemiş bir monolit zamanla literatürde "Big Ball of Mud" (Büyük Çamur Topu) olarak adlandırılan, hangi sınıfın hangi veritabanı tablosunu değiştirdiğinin takip edilemediği sıkı bağımlı (tightly coupled) bir yığına dönüşür.

Bu aşamada ortaya çıkan en büyük sorunlar şunlardır: En ufak bir fatura şablonu veya e-posta metni değişikliği için bile tüm sistemin yeniden derlenip test edilmesi ve dağıtılması gerekir. Git birleştirme çakışmaları (merge conflicts) günlük geliştirme hızını felç eder. Daha da tehlikelisi, raporlama veya PDF üretimi modülündeki bir bellek sızıntısı (Out of Memory - OOM) ya da CPU darboğazı, tüm uygulama sunucusu sürecini çökerterek ödeme alma ve sipariş oluşturma gibi hayati fonksiyonları da anında devre dışı bırakır (Single Point of Failure). Ayrıca monolitik bir yapıda teknoloji yığınına (Tech Stack) kilitlenme yaşanır; örneğin 8 yıl önce seçilen bir framework veya dil sürümünü yükseltmek tüm kodu etkilediği için aylarca süren riskli göç projeleri gerektirir.

Modüler Monolit (Modular Monolith): İki Dünya Arasındaki Altın Köprü

Birçok yazılım ekibi monolitik yapının karmaşasından kaçmak için henüz organizasyonel ve operasyonel olarak hazır olmadan doğrudan mikroservislere geçmekte ve bu kez "Dağıtık Monolit" (Distributed Monolith) adı verilen çok daha tehlikeli bir anti-pattern içine düşmektedir. Oysa modern yazılım mimarisinde klasik monolit ile mikroservisler arasında üçüncü ve son derece güçlü bir alternatif vardır: Modüler Monolit (Modular Monolith).

Modüler monolit; uygulamanın fiziksel olarak hala tek bir dağıtım paketi (single deployment unit) olarak çalışmaya devam ettiği, ancak kod tabanının mantıksal olarak tamamen izole edilmiş, bağımsız iş alanlarına (Bounded Contexts / Domain Modules) bölündüğü mimaridir. Bu yapıda Sipariş, Katalog, Ödeme, Kargo ve Kullanıcı modülleri birbirinin iç sınıflarına (internal classes) veya veritabanı tablolarına doğrudan erişemez. Modüller arası SQL JOIN sorguları mimari testlerle (örneğin Java'da ArchUnit, .NET'te NetArchTest) kesin olarak yasaklanır. Modüller yalnızca iyi tanımlanmış halka açık arayüzler (Public Interfaces / Contracts) veya bellek içi asenkron olay mesajlaşması (In-Process Event Bus / MediatR) üzerinden haberleşir.

Modüler Monolit ve Mikroservis Veritabanı İzolasyonu Mimarisi
Monolitik ortak veritabanı yapısından Modüler Monolit şema ayrımına ve Mikroservislerde tam Veritabanı İzolasyonuna (Database-per-Service) geçiş mimarisi.

Neden Önce Modüler Monolit Tercih Edilmeli?

Yeni bir yazılım ürünü geliştirirken iş alanının sınırları (Domain Boundaries) ilk günden tam olarak bilinemez. Eğer sınırları yanlış çizilmiş bir sistemi 15 mikroservise bölerseniz, bir iş kuralını değiştirmek için 5 farklı mikroserviste aynı anda kod değiştirip sıralı dağıtım yapmanız gerekir. Modüler monolit ise ağ gecikmesi ve dağıtık işlem karmaşıklığı olmadan modül sınırlarını kod içinde hızlıca yeniden düzenlemenize (refactoring) olanak tanır. Modül sınırları olgunlaştığında ve belirli bir modül gerçekten bağımsız ölçeklenmeye ihtiyaç duyduğunda, o modül zaten izole bir veritabanı şemasına ve temiz bir arayüze sahip olduğu için birkaç gün içinde ayrı bir mikroservis olarak dışarı çıkarılabilir.

Mikroservis Mimarisi (Microservices Architecture) Nedir?

Mikroservis mimarisi, büyük ve karmaşık bir yazılım uygulamasının; her biri tek bir iş yeteneğine (Single Business Capability) odaklanan, kendi yaşam döngüsüne sahip, kendi veritabanını yöneten, bağımsız olarak geliştirilebilen, dağıtılabilen (deployable) ve ölçeklenebilen küçük, otonom servisler topluluğu olarak tasarlanmasıdır. Martin Fowler ve Sam Newman gibi yazılım mimarlarının standartlaştırdığı bu yaklaşımda sistem, Eric Evans'ın Domain-Driven Design (DDD - Alan Güdümlü Tasarım) metodolojisindeki Bounded Context (Sınırlı Bağlam) kavramına göre parçalanır.

Özellikle modern Headless Commerce ve mikroservis API mimarisi kullanan yüksek hacimli dijital platformlarda; Arama Servisi, Sepet Servisi, Dinamik Fiyatlandırma ve Kampanya Motoru, Ödeme Servisi ve Lojistik Entegrasyon Servisi birbirinden tamamen ayrı süreçler (processes) ve konteynerler olarak çalışır. İstemci (Web, iOS, Android veya IoT cihazı) doğrudan yüzlerce mikroservise bağlanmaz; bunun yerine trafiği yönlendiren, kimlik doğrulaması (JWT / OAuth2) yapan, SSL sonlandıran ve hız sınırlaması (rate limiting) uygulayan bir API Gateway (API Ağ Geçidi) veya istemci tipine özel optimize edilmiş BFF (Backend for Frontend) katmanı üzerinden iletişim kurar.

Mikroservis Mimarisinin 5 Temel Tasarım Prensibi

  1. Bağımsız Dağıtılabilirlik (Independent Deployability): Bir mikroserviste yapılan kod değişikliği, diğer hiçbir servisin yeniden başlatılmasını, test edilmesini veya dağıtılmasını gerektirmeden gün içinde onlarca kez canlı ortama (production) alınabilir. Eğer iki servisi aynı anda canlıya almak zorundaysanız, gerçek bir mikroservis mimarisine sahip değilsiniz demektir.
  2. Servis Başına Veritabanı İzolasyonu (Database-per-Service): Mikroservislerin en katı mimari kuralıdır. Hiçbir mikroservis başka bir mikroservisin veritabanına doğrudan SQL veya NoSQL sorgusu atamaz. Her servis kendi verisinin tek sahibidir ve verisini dış dünyaya yalnızca API veya olaylar (Events) üzerinden açar.
  3. Teknoloji Heterojenliği (Polyglot Programming & Persistence): Her servis kendi problemine en uygun programlama dili, çalışma zamanı ve veritabanı ile yazılabilir. Örneğin; gerçek zamanlı öneri motoru Python ve Neo4j (Graf veritabanı) ile, yüksek frekanslı ödeme servisi Go ve PostgreSQL ile, sepet servisi Node.js ve Redis ile, tam metin ürün arama servisi ise Rust ve Elasticsearch ile geliştirilebilir.
  4. Hata İzolasyonu ve Dayanıklılık (Fault Isolation & Resilience): Tavsiye (Recommendation) veya Yorumlar servisi çöktüğünde ya da veritabanı yanıt veremediğinde, Circuit Breaker (Devre Kesici) deseni devreye girer; kullanıcıya varsayılan önbellek verisi gösterilir (Graceful Degradation) ancak sepete ekleme ve satın alma akışı kesintisiz çalışmaya devam eder.
  5. Hassas ve Bağımsız Ölçeklenebilirlik (Granular Auto-Scaling): Büyük indirim kampanyalarında (Black Friday vb.) yalnızca yoğun yük altında kalan "Ürün Katalog" ve "Sepet" servisleri Kubernetes üzerinde 100 kopyaya (pod) çıkarılırken, az kullanılan "Fatura Arşiv" servisi 2 kopyada tutularak bulut sunucu maliyetlerinde devasa optimizasyon sağlanır.

Veritabanı İzolasyonu ve Dağıtık Veri Yönetimi: Database-per-Service

Monolitik yapıdan mikroservislere geçişte yazılım mühendislerinin karşılaştığı en büyük zihinsel ve teknik paradigma değişimi veritabanı katmanında yaşanır. Monolitik dünyada SELECT * FROM Orders JOIN Users ON ... JOIN Products ON ... şeklinde tek bir SQL sorgusuyla tüm ekran verisini çekmek mümkündür. Ancak mikroservislerde ortak bir veritabanı kullanmak kesinlikle yasaktır; çünkü ortak veritabanı şeması tüm servisleri birbirine görünmez bir göbek bağıyla bağlar (Tight Coupling) ve şema değişikliklerini imkansız hale getirir.

Database-per-Service deseninde Sipariş Servisi yalnızca OrdersDB'ye, Müşteri Servisi yalnızca CustomersDB'ye, Stok Servisi ise yalnızca InventoryDB'ye erişebilir. Peki bu durumda yabancı anahtar kısıtlamaları (Foreign Key Constraints), çoklu tablo birleştirmeleri (JOIN) ve atomik işlemler (Transactions) nasıl çözülür?

1. Servisler Arası Veri Sorgulama: API Composition ve CQRS Deseni

Farklı mikroservislerdeki verileri birleştirerek bir yönetim paneli veya müşteri sipariş geçmişi ekranı oluşturmak için iki ana mimari desen kullanılır:

  • API Composition (API Birleştirme): API Gateway veya özel bir birleştirici servis (Aggregator / BFF), Sipariş, Ürün ve Kargo mikroservislerine paralel (asenkron) ağ istekleri atar, dönen JSON veya Protobuf yanıtlarını bellekte (in-memory join) birleştirerek istemciye tek bir yanıt olarak sunar. Basit sorgular için idealdir ancak çok fazla servisin birleştirilmesi gerektiğinde ağ gecikmesini artırabilir.
  • CQRS (Command Query Responsibility Segregation): Yazma (Command) ve okuma (Query) sorumlulukları fiziksel olarak birbirinden ayrılır. Sipariş, Müşteri ve Kargo servislerinde bir veri değiştiğinde Apache Kafka veya RabbitMQ üzerinden bir olay (Domain Event) yayınlanır. Okuma tarafındaki özel bir "Sipariş Görünüm Servisi" bu olayları dinleyerek kendi okuma odaklı (denormalize edilmiş Elasticsearch veya MongoDB) veritabanını günceller. Böylece en karmaşık filtreleme ve raporlama sorguları bile sıfır JOIN maliyetiyle milisaniyeler içinde tek bir okuma tablosundan yanıtlanır.
Saga Pattern Dağıtık İşlem Yönetimi ve Bağımsız Ölçekleme
Mikroservis mimarisinde Saga Pattern (Choreography ve Orchestration) ile dağıtık veri tutarlılığı ve bağımsız yatay ölçekleme yapısı.

2. Dağıtık İşlemler (Distributed Transactions) ve Saga Pattern

İlişkisel bir veritabanında ACID garantisi altındaki işlemleri dağıtık mikroservislerde uygulamak için geçmişte kullanılan İki Aşamalı Onay (Two-Phase Commit - 2PC / XA Transactions) protokolü, tüm katılımcı servisleri işlem bitene kadar kilitlediği (blocking), yüksek gecikme yarattığı ve CAP teoremine göre erişilebilirliği (Availability) düşürdüğü için modern bulut mimarilerinde terk edilmiştir. Bunun yerine Nihai Tutarlılık (Eventual Consistency) prensibine dayanan Saga Pattern kullanılır.

Bir Saga, her mikroservisin kendi yerel veritabanında gerçekleştirdiği bir dizi yerel işlemden (local ACID transactions) oluşur. Her yerel işlem tamamlandığında bir sonraki adımı tetikleyen bir mesaj veya olay yayınlanır. Eğer zincirdeki herhangi bir adım başarısız olursa (örneğin kredi kartı limiti yetersiz çıkarsa veya stok tükenmişse), Saga daha önce başarılı olmuş adımları geri almak için Telafi Edici İşlemler (Compensating Transactions) çalıştırır. Saga Pattern iki farklı topolojiyle uygulanır:

  • Koreografi Tabanlı Saga (Choreography-based Saga): Merkezi bir koordinatör yoktur; servisler olaylara (Events) abone olarak birbirini tetikler. Sipariş Servisi siparişi PENDING (Beklemede) durumuyla kaydeder ve OrderCreated olayını yayınlar; Stok Servisi bunu dinleyip stoğu rezerve eder ve StockReserved olayını yayınlar; Ödeme Servisi bunu dinleyip ücreti tahsil eder ve PaymentCompleted olayını yayınlar. Eğer ödeme reddedilirse Ödeme Servisi PaymentFailed olayını fırlatır; Stok Servisi bunu yakalayıp rezerve ettiği stoğu serbest bırakır (Compensating Transaction), Sipariş Servisi ise siparişi CANCELLED durumuna çeker. 2 ila 4 servis içeren akışlar için gevşek bağlı (loosely coupled) ve hızlı bir çözümdür.
  • Orkestrasyon Tabanlı Saga (Orchestration-based Saga): Süreci baştan sona yöneten merkezi bir durum makinesi (State Machine / Saga Orchestrator; örneğin Temporal.io, Camunda veya özel bir Orkestratör Servisi) bulunur. Sipariş Orkestratörü sırasıyla Stok Servisine "Stoğu rezerve et", ardından Ödeme Servisine "Ödemeyi tahsil et" komutlarını (Command) gönderir. Bir hata oluştuğunda hangi telafi edici komutun hangi sırayla çağrılacağına, kaç kez yeniden deneneceğine (Retry) ve zaman aşımı (Timeout) yönetimine Orkestratör karar verir. Çok adımlı, karmaşık kurumsal iş akışlarında döngüsel bağımlılıkları (cyclic dependencies) önler ve uçtan uca görünürlük sağlar.
// Orkestrasyon Tabanlı Saga Durum Makinesi (Örnek Mimari Akış)
class OrderSagaOrchestrator {
  async executeOrderFlow(orderData) {
    try {
      await OrderService.createPendingOrder(orderData.id);
      await InventoryService.reserveStock(orderData.id, orderData.items);
      await PaymentService.chargeCard(orderData.id, orderData.customerId, orderData.totalAmount);
      await ShippingService.scheduleDelivery(orderData.id, orderData.address);
      await OrderService.confirmOrder(orderData.id);
    } catch (error) {
      // Telafi Edici İşlemler (Compensating Transactions - Ters Sırayla Rollback)
      await PaymentService.refundIfCharged(orderData.id);
      await InventoryService.releaseReservedStock(orderData.id, orderData.items);
      await OrderService.cancelOrder(orderData.id, error.message);
    }
  }
}

3. Transactional Outbox Pattern ve İdempotent (Idempotency) Tasarım

Mikroservislerde en sık yapılan hatalardan biri, yerel veritabanına kayıt attıktan hemen sonra mesaj kuyruğuna (Kafka/RabbitMQ) olay göndermeye çalışmaktır (Dual Write Problem). Eğer veritabanı kaydı başarılı olur ancak o milisaniyede ağ koparsa ve Kafka'ya mesaj gönderilemezse, sistem tutarsız (inconsistent) kalır. Bunu çözmek için Transactional Outbox Pattern kullanılır: Sipariş Servisi hem Orders tablosuna yeni siparişi yazar hem de aynı yerel ACID transaction içinde aynı veritabanındaki OutboxMessages tablosuna yayınlanacak olayı kaydeder. Ardından Debezium (CDC - Change Data Capture) veya arka planda çalışan bir Relay işçisi OutboxMessages tablosunu okuyup mesajı Kafka'ya garantili olarak iletir (At-Least-Once Delivery). Mesaj birden fazla kez iletilebileceği için alıcı servislerin Idempotent (aynı MessageID veya Idempotency-Key ile gelen mükerrer mesajları tespit edip işlemi yalnızca bir kez uygulayan) olarak tasarlanması şarttır.

Monolitten Mikroservise Aşamalı Göç: Strangler Fig ve Anti-Corruption Layer

Yıllardır çalışan devasa bir kurumsal monolitik sistemi bir gecede kapatıp sıfırdan mikroservis olarak yazmaya çalışmak (Big Bang Rewrite), yazılım tarihinde en çok başarısızlıkla sonuçlanan stratejidir. İş kuralları zamanla kodun içine gömüldüğü için sıfırdan yazım sürecinde hem mevcut müşteriler kaybedilir hem de iki ayrı sistemi yıllarca paralel geliştirmek zorunda kalınır. Bunun yerine aşamalı modernizasyon sağlayan üç adımlı mühendislik stratejisi uygulanır:

  1. Kenar Servislerden Başlama (Edge Extraction): İlk aşamada monolitin en az bağımlılığa sahip ancak yüksek kaynak tüketen modülleri (örneğin Bildirim Gönderimi, Rapor Üretimi, Görsel İşleme veya Arama Motoru) mikroservis olarak ayrılır. Ana iş mantığı (Sipariş/Muhasebe) en son aşamaya bırakılır.
  2. Strangler Fig Pattern (Boğucu İncir Deseni): Monolitik uygulamanın önüne bir API Gateway (Kong, Envoy veya NGINX) yerleştirilir. Yeni mikroservis hazır olduğunda, API Gateway üzerindeki ilgili URL rotası (örneğin /api/v2/search) eski monolit yerine yeni mikroservise yönlendirilir. Zamanla monolitin içindeki modüller tek tek dışarı alındıkça eski monolit küçülür ve sonunda tamamen emekliye ayrılır.
  3. Anti-Corruption Layer (ACL - Bozulma Önleyici Katman): Yeni yazılan temiz mikroservisin, eski monolitin karmaşık ve bozuk veri modelinden (legacy schema) etkilenmemesi için iki sistem arasına bir çevirici adaptör katmanı (ACL) yerleştirilir. ACL katmanı, eski sistemin veri yapılarını yeni mikroservisin Domain-Driven Design (DDD) modeline tercüme ederek mimari kirlenmeyi engeller.

İletişim, Dayanıklılık (Resilience) ve Gözlemlenebilirlik Katmanları

Monolitik bir yapıyı 50 mikroservise böldüğünüzde, kod içindeki karmaşıklığı yok etmiş olmazsınız; onu kod katmanından ağ, güvenlik ve altyapı katmanına taşımış olursunuz. Bulut teknolojisi ve SaaS altyapıları üzerinde çalışan bir mikroservis ekosisteminin üretim ortamında (production) ayakta kalabilmesi için şu dört mühendislik katmanı zorunludur:

  • API Gateway ve Service Mesh (Istio / Linkerd): Dış dünyadan gelen Kuzey-Güney (North-South) trafiğini Kong, AWS API Gateway veya Envoy gibi bir ağ geçidi karşılarken; küme içindeki mikroservislerin kendi arasındaki Doğu-Batı (East-West) trafiğini Service Mesh yönetir. Sidecar proxy mimarisi sayesinde kod yazmadan servisler arası karşılıklı TLS (mTLS) şifreleme, otomatik trafik yönlendirme ve ağırlıklı kanarya dağıtımı (Canary Deployment) sağlanır.
  • Dayanıklılık Desenleri (Circuit Breaker, Bulkhead, Retry): Bir mikroservis yanıt vermekte geciktiğinde onu çağıran diğer servislerin de iş parçacığı havuzlarının (thread pools) dolup zincirleme olarak çökmesini (Cascading Failure) engellemek için Circuit Breaker (Devre Kesici) kullanılır. Hata oranı eşiği aşıldığında devre açılır ve çağrılar bekletilmeden anında varsayılan yanıtla (Fallback) döndürülür. Ayrıca Exponential Backoff + Jitter ile akıllı yeniden deneme ve Bulkhead ile kaynak izolasyonu uygulanır.
  • Dağıtık İzleme (Distributed Tracing): Tek bir kullanıcı isteğinin 12 farklı mikroservisten geçerken hangi serviste kaç milisaniye kaybettiğini veya hangi SQL sorgusunda darboğaz yaşadığını görmek için OpenTelemetry standardı ile Jaeger veya Tempo kullanılır. Her isteğe ağ geçidinde benzersiz bir Trace-ID ve her servis adımına bir Span-ID atanır.
  • Merkezi Loglama ve Altın Sinyaller (Golden Signals): Yüzlerce konteynerin ürettiği yapılandırılmış JSON loglar ELK Stack (Elasticsearch, Logstash, Kibana) veya Grafana Loki üzerinde toplanır; Prometheus ile Google SRE metodolojisinin dört altın sinyali (Gecikme/Latency, Trafik/Traffic, Hatalar/Errors ve Doygunluk/Saturation) gerçek zamanlı izlenir.

Ayrıca eski nesil monolitik kurumsal yazılımların modern mikroservis mimarilerine dönüştürülmesi sürecinde, dokümantasyonu olmayan mevcut iş kurallarını ve gizli bağımlılıkları eksiksiz çıkarmak için yapay zeka destekli tersine mühendislik (REA) yöntemleri büyük rol oynamaktadır. Benzer şekilde kurum içi operasyon ve bayi yönetim panelleri geliştirilirken her ekranı sıfırdan özel kodla yazmak yerine No-Code uygulama geliştirme platformları ile mikroservis API'lerini tüketen hızlı arayüzler inşa etmek mühendislik eforunu optimize eder. Hatta merkeziyetsiz veri doğrulama ve kriptografik mutabakat gerektiren yeni nesil sistemlerde mikroservisler, Web3 ve merkezsiz web mimarisi üzerindeki akıllı sözleşmelerle hibrit şekilde entegre edilmektedir.

Monolitik, Modüler Monolit ve Mikroservis Karşılaştırma Tablosu

Mimari karar verirken teknik ve operasyonel kriterleri objektif olarak değerlendirebilmeniz için üç yaklaşımın temel farklarını aşağıdaki tabloda kapsamlı biçimde karşılaştırdık:

Karşılaştırma Kriteri Klasik Monolitik Mimari Modüler Monolit (Modular Monolith) Mikroservis Mimarisi (Microservices)
Dağıtım Birimi (Deployment Unit) Tek parça (Single Artifact) Tek parça (Mantıksal olarak ayrık modüller) Her servis bağımsız dağıtılır (Konteyner/Pod)
Veritabanı Topolojisi Tek merkezi paylaşımlı veritabanı Tek veritabanı içinde izole şemalar / tablolar Servis başına tam izole veritabanı (Polyglot)
Veri Tutarlılığı (Consistency) Anlık güçlü tutarlılık (ACID Transactions) Güçlü tutarlılık veya bellek içi olaylar Nihai tutarlılık (Eventual Consistency / Saga)
Modüller Arası İletişim Doğrudan bellek içi metot çağrısı Bellek içi arayüzler (Public API / Event Bus) Ağ üzerinden (gRPC, REST, Kafka, RabbitMQ)
Ölçeklenebilirlik (Scaling) Tüm uygulama birlikte kopyalanır (Dikey/Yatay) Tüm uygulama birlikte ölçeklenir Sadece darboğaz yaşayan servis bağımsız ölçeklenir
Hata İzolasyonu (Fault Isolation) Düşük (Tek bir bellek hatası tüm sistemi çökertir) Orta (Süreç ortak olduğu için risk devam eder) Çok Yüksek (Circuit Breaker ile hata izole edilir)
Teknoloji Çeşitliliği Tek dil ve framework zorunluluğu Tek dil ve çalışma zamanı (Runtime) Tam özgürlük (Her servis farklı dilde yazılabilir)
Operasyonel ve DevOps Maliyeti Çok Düşük (Basit CI/CD ve sunucu yönetimi) Düşük (Monolit kadar kolay operasyon) Yüksek (Kubernetes, Service Mesh, Tracing şart)
İdeal Ekip ve Proje Ölçeği 1-10 kişilik ekipler, MVP ve erken aşama ürünler 10-40 kişilik ekipler, büyüyen kurumsal ürünler 40+ kişilik çoklu otonom takımlar, yüksek ölçek

Hangi Durumda Hangi Mimari Seçilmeli? (Monolith-First Yaklaşımı)

Yazılım dünyasında altın kural şudur: "Mikroservisler, teknik bir problemden ziyade organizasyonel ölçeklenme ve bağımsız dağıtım problemini çözer." Melvin Conway'in 1967'de ortaya koyduğu Conway Yasası (Conway's Law) uyarınca, organizasyonların tasarladığı yazılım sistemleri, o organizasyonun iç iletişim yapısının birebir kopyasıdır. Eğer 6 kişilik tek bir yazılım ekibiniz varsa ve henüz ürün-pazar uyumunu (Product-Market Fit) arıyorsanız, 25 mikroservisli bir mimari kurmak projeyi daha doğmadan ağ hataları, dağıtık transaction sorunları ve Kubernetes bakım yüküyle yavaşlatacaktır.

Uzman Tavsiyesi (Modüler Monolit ile Başlayın): Yeni bir projeye başlarken sınırları Domain-Driven Design (DDD) ile net çizilmiş bir Modüler Monolit inşa edin. Alan sınırlarını (Bounded Contexts) gerçek kullanıcı trafiği ve değişen iş gereksinimleriyle doğrulayın. Zamanla belirli bir modül (örneğin Görüntü İşleme, Arama, Kampanya Hesaplama veya Ödeme) çok yüksek CPU/RAM tüketmeye başladığında ya da o modüle bakan takım bağımsız dağıtım hızına ihtiyaç duyduğunda, sadece o modülü mikroservis olarak dışarı çıkarın.

Sıkça Sorulan Sorular (SSS)

1. Mikroservis mimarisi her zaman monolitik mimariden daha mı hızlıdır?

Hayır, aksine tekil bir isteğin uçtan uca yanıt süresi (latency) açısından monolitik mimari genellikle daha hızlıdır. Çünkü monolitik yapıda modüller arası geçişler aynı bellek (RAM) içinde nanosaniyeler mertebesinde gerçekleşirken, mikroservislerde verinin JSON veya Protobuf olarak serileştirilip ağ üzerinden (HTTP/TCP) başka bir sunucuya gitmesi ve tekrar çözülmesi milisaniyeler ekler. Mikroservislerin performans üstünlüğü tekil işlem süresinden değil; milyonlarca eşzamanlı isteği darboğaz olmadan bağımsız yatay ölçekleme (horizontal scaling) ve hata izolasyonu ile karşılayabilme kapasitesinden gelir.

2. İki mikroservis aynı veritabanını paylaşabilir mi?

Mimari standartlara göre kesinlikle paylaşmamalıdır. İki servisin aynı veritabanı tablolarına doğrudan okuma ve yazma yapması "Shared Database Anti-Pattern" olarak adlandırılır. Bir servis tablo şemasında bir sütun adını veya veri tipini değiştirdiğinde diğer servis anında çöker, veritabanı kilitlenmeleri (locks) tüm servisleri etkiler ve bağımsız dağıtılabilirlik (independent deployability) ilkesi tamamen ortadan kalkar. Her servis kendi özel veritabanına veya en azından tamamen izole edilmiş kendi şemasına sahip olmalıdır.

3. Dağıtık Monolit (Distributed Monolith) nedir ve nasıl önlenir?

Dağıtık monolit; fiziksel olarak birden fazla servise bölünmüş olmasına rağmen, servislerin birbirine senkron zincirleme HTTP çağrılarıyla veya ortak veritabanıyla sıkı sıkıya bağlı olduğu, bir servisi güncellemek için diğerlerinin de eşzamanlı dağıtılmasını gerektiren en kötü mimari senaryodur. Hem monolitin bağımlılık sorunlarını hem de mikroservislerin ağ karmaşıklığını aynı anda yaşatır. Önlemek için Domain-Driven Design ile doğru sınırlar çizilmeli, veritabanları ayrılmalı ve servisler arası iletişimde olay güdümlü (Event-Driven) asenkron mesajlaşma tercih edilmelidir.

4. Monolitik bir uygulamayı mikroservislere taşırken nereden başlanmalı?

Mevcut sistemi tamamen durdurup sıfırdan yazmak (Big Bang Rewrite) çok yüksek başarısızlık ve iş kaybı riski taşır. Bunun yerine Martin Fowler'ın tanımladığı Strangler Fig Pattern (Boğucu İncir Deseni) uygulanmalıdır. Önce monolitin önüne bir API Gateway yerleştirilir; ardından yeni eklenecek özellikler veya en çok ölçeklenme sorunu yaşayan kenar modüller (örneğin Bildirim, Kargo Takip veya Raporlama) bağımsız mikroservis olarak yazılır, eski monolitle araya bir Anti-Corruption Layer (ACL) konur ve API Gateway üzerinden trafik aşamalı olarak yeni servislere yönlendirilir.

5. Mikroservislerde kaç satır kod olmalı, "Mikro" ne kadar küçüktür?

Mikroservisin büyüklüğü kod satırı sayısıyla (LOC) ölçülmez; aşırı küçük servisler (Nano-services) yönetilemez bir ağ trafiği ve operasyonel kaos yaratır. Doğru ölçüt, Tek Sorumluluk İlkesi (Single Responsibility Principle) ve Bounded Context (Sınırlı Bağlam) kavramıdır. Bir mikroservis, Amazon'un ünlü "Two-Pizza Team" kuralında olduğu gibi 5 ila 8 kişilik tek bir otonom ekibin uçtan uca anlayabileceği, geliştirebileceği ve 7/24 bakımını üstlenebileceği bir iş yeteneğini (örneğin "Kredi Kartı Ödeme Tahsilatı") kapsamalıdır.

Paylaş

Yozel

Codex haberleri en az iki bağımsız kaynakla doğrulanır; düzeltmeler yazının altında tarih ve saatle belirtilir. Yayın ilkelerimiz