.NET MİCROSERVİCES NEDİR? İLETİŞİM, MESAJLAŞMA VE DAYANIKLILIK DESENLERİ
Tek bir uygulamayı “daha küçük parçalara bölmek” kulağa basit gelir; asıl zor olan, o parçaların birlikte güvenilir biçimde çalışmasını sağlamaktır. .NET ekosisteminde microservices yaklaşımı, bağımsız dağıtılabilen servislerle hız ve ölçek kazandırırken; iletişim, mesajlaşma ve dayanıklılık desenlerini doğru kurgulamazsanız gecikme, hata zinciri ve gözlemlenebilirlik boşlukları hızla büyür.
Bu yazıda .NET microservices yaklaşımını pratik bir çerçeveyle ele alacağız: servisler arası senkron iletişim (REST/gRPC), asenkron mesajlaşma (event-driven), tutarlılık stratejileri, dayanıklılık (retry, timeout, circuit breaker) ve üretimde olmazsa olmaz gözlemlenebilirlik (logging/metrics/tracing). Amaç, “hangi teknoloji”den çok “hangi problem için hangi desen” sorusuna net cevap vermek.
Okurken aklınızda şu ilke kalsın: Microservices, dağıtık sistem demektir; dağıtık sistemler ise ağ gecikmesi, kısmi hata ve veri tutarlılığı gibi konuları uygulama geliştirmenin merkezine taşır. Doğru desenler, bu gerçekleri yönetilebilir hale getirir.
.NET microservices nedir ve neden tercih edilir?
Bağımsız dağıtım ve ekip ölçekleme
Microservices; iş yeteneklerini (bounded context) ayrı servisler olarak modelleyip her servisi bağımsız geliştirme, test etme ve dağıtma yaklaşımıdır. Böylece bir servisteki değişiklik diğerlerini bekletmeden üretime çıkabilir. Bu, CI/CD hattını hızlandırır ve ekiplerin paralel çalışmasını kolaylaştırır.
Hata izolasyonu ve ölçekleme stratejileri
Monolitte tek bir hata tüm sistemi etkileyebilir; microservices mimarisinde ise doğru sınırlar ve altyapı ile hataları izole etmek mümkün olur. Örneğin ödeme servisi yoğunken stok servisini aynı oranda ölçeklemek zorunda kalmazsınız. Ancak bu fayda, servisler arası bağımlılıkların doğru yönetilmesiyle ortaya çıkar.
- Tek sorumluluk: Servis sınırları net ve iş odaklı olmalı.
- Bağımsız veri sahipliği: Her servis kendi verisinin sahibi olmalı.
- Sözleşme odaklı entegrasyon: API sözleşmeleri değişime dayanıklı tasarlanmalı.

Servisler arası iletişim: Senkron yaklaşım (REST ve gRPC)
REST ile sözleşme ve versiyonlama
Senkron iletişimde en yaygın yaklaşım HTTP tabanlı REST API’lerdir. REST, geniş ekosistem desteği ve araç seti (OpenAPI/Swagger) ile güçlüdür; fakat dağıtık çağrılar arttıkça gecikme ve hata zinciri riski büyür. Bu nedenle API tasarımında versiyonlama, geriye dönük uyumluluk ve idempotency gibi ilkeler belirleyici olur.
API sözleşmesini yönetmenin pratik yolu: breaking change riskini minimize eden alan ekleme/opsiyonellik stratejileri, “yeni endpoint” açma yaklaşımı ve tüketici odaklı sözleşme testleridir. Bu noktada consumer-driven contract testing (ör. Pact) gibi pratikler, servis bağımlılıklarını daha güvenli hale getirir.
gRPC ile düşük gecikme ve güçlü tip güvenliği
Yoğun servis içi trafiği olan sistemlerde gRPC, HTTP/2 üzerinden ikili protokol ile düşük gecikme ve daha küçük payload sağlar. Ayrıca .proto sözleşmesiyle güçlü tip güvenliği ve otomatik client üretimi elde edilir. Bununla birlikte gateway/edge tarafında REST ihtiyacı devam edebilir; bu yüzden sık görülen desen, içeride gRPC, dışarıda REST kullanmaktır.
Mesajlaşma ve event-driven mimari: Asenkron yaklaşım
Neden mesajlaşma? Gevşek bağlılık ve akış dayanıklılığı
Event-driven yaklaşım, servislerin birbirini doğrudan çağırmak yerine olaylar üzerinden haberleşmesini sağlar. Bu; gevşek bağlılığı artırır, “anlık erişilebilirlik” baskısını azaltır ve backpressure gibi üretim sorunlarını daha yönetilebilir kılar. Örneğin sipariş oluşturma, stok ayırma ve faturalama süreçleri aynı anda senkron çağrılarla zincirlenmek yerine olaylarla ilerleyebilir.
Mesajlaşmada temel tercih, “komut” ile “event” ayrımını net yapmaktır: Command bir işi yaptırmayı, event ise olmuş bir gerçeği duyurmayı temsil eder. Yanlış ayrım, servislerin sorumluluklarını bulanıklaştırır.
Broker seçimi ve teslimat garantileri
RabbitMQ, Kafka, Azure Service Bus gibi seçenekler farklı ihtiyaçlara hitap eder. RabbitMQ çoğu iş uygulamasında queue temelli işleme için güçlüdür; Kafka ise yüksek hacimli akış ve log temelli event saklama için öne çıkar. Hangi aracı seçerseniz seçin, “en az bir kez” (at-least-once) teslimatın getirdiği çoğul işlem riskini idempotency ile yönetmeniz gerekir.

Dayanıklılık desenleri: Retry, Timeout, Circuit Breaker ve Bulkhead
Kısmi hata gerçeği ve “başarısızlığı tasarlamak”
Dağıtık sistemlerde hata bir istisna değil, beklenen bir durumdur: DNS gecikmesi, geçici ağ kopması, bağımlı servisin yavaşlaması, rate limit… Bu yüzden dayanıklılık desenleri, microservices mimarisinin çekirdeğidir. Amaç, hatayı saklamak değil; kontrollü biçimde sınırlamak ve kullanıcı deneyimini korumaktır.
Polly ile HTTP dayanıklılığı (örnek)
Aşağıdaki örnek, .NET’te HttpClientFactory ve Polly ile retry, timeout ve circuit breaker kurgusunu gösterir. Burada kritik nokta, retry stratejisinin her çağrıya körlemesine uygulanmaması; yalnızca geçici hatalarda ve idempotent işlemlerde devreye alınmasıdır.
using Polly;
using Polly.Extensions.Http;
using System.Net.Http;
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => (int)msg.StatusCode == 429) // rate limit
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: attempt => TimeSpan.FromMilliseconds(200 * Math.Pow(2, attempt))
);
var circuitBreakerPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 5,
durationOfBreak: TimeSpan.FromSeconds(30)
);
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(2));
builder.Services.AddHttpClient("catalog", client =>
{
client.BaseAddress = new Uri("https://catalog-api/");
})
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(timeoutPolicy)
.AddPolicyHandler(circuitBreakerPolicy);Bu desenler birlikte kullanıldığında, yavaşlayan bir bağımlı servis tüm sistemi “yavaşlatan bir bataklığa” dönüştürmez. Bulkhead (izolasyon) ve kuyruklama stratejileriyle birleşince, yük patlamalarında bile sistemin ana akışı korunabilir.
Dağıtık veri ve tutarlılık: Saga, Outbox ve idempotency
Veri sahipliği ve “eventual consistency”
Microservices’te her servis kendi verisinin sahibi olduğunda, çapraz servis tek bir ACID transaction ile yönetilemez. Bu, tutarlılığın zamana yayıldığı bir modele geçmek anlamına gelir. Burada kritik soru şudur: İş süreci hangi noktada “tamamlandı” sayılmalı ve kullanıcıya hangi ara durumlar gösterilmeli?
Saga deseni: Orkestrasyon ve koreografi
Saga, çok adımlı iş süreçlerini yönetmek için kullanılan bir desendir. Orkestrasyon yaklaşımında merkezi bir saga yöneticisi akışı kontrol eder; koreografide ise servisler olaylara tepki vererek süreci ilerletir. Orkestrasyon, akışı tek yerden görmek açısından kolaylık sağlar; koreografi ise bağımlılıkları azaltır ancak izleme ve hata yönetimi daha disiplinli olmalıdır.
Outbox ve idempotency ile güvenilir yayınlama
Veritabanına yazıp sonra mesaj yayınlamak, iki ayrı işlem olduğu için tutarsızlık yaratabilir. Outbox deseni, olayları aynı veritabanı transaction’ında “outbox” tablosuna yazıp güvenilir bir işleyiciyle broker’a yayınlayarak bu riski azaltır. Tüketici tarafında ise idempotency (ör. processed-message tablosu) aynı mesajın ikinci kez işlenmesini güvenle engeller.
Mesajlaşma örneği: Event publish/consume (MassTransit + RabbitMQ)
Olay sözleşmesi ve tüketici mantığı
Aşağıdaki örnek, sipariş oluşturulduğunda bir event yayınlamayı ve stok servisinde tüketmeyi gösterir. Gerçek hayatta hata yönetimi, tekrar deneme ve dead-letter stratejileri eklenmelidir; ayrıca tüketicide idempotency kontrolü yapılmalıdır.
// Contracts
public record OrderCreated(Guid OrderId, Guid CustomerId, decimal Total, DateTime OccurredAt);
// Publisher (Order Service)
public class OrdersController : ControllerBase
{
private readonly IPublishEndpoint _publish;
public OrdersController(IPublishEndpoint publish) => _publish = publish;
[HttpPost("/orders")]
public async Task<IActionResult> Create(CreateOrderRequest req)
{
var orderId = Guid.NewGuid();
// ... persist order
await _publish.Publish(new OrderCreated(orderId, req.CustomerId, req.Total, DateTime.UtcNow));
return Accepted(new { orderId });
}
}
// Consumer (Stock Service)
public class OrderCreatedConsumer : IConsumer<OrderCreated>
{
public async Task Consume(ConsumeContext<OrderCreated> context)
{
var evt = context.Message;
// idempotency check should be here in real systems
// reserve stock for the order
await Task.CompletedTask;
}
}Event-driven tasarımda en önemli konulardan biri, event şemasının “tüketiciler büyüdükçe” yönetilebilir kalmasıdır. Versiyonlama stratejisi, backward compatibility ve şema evrimi planı olmadan event’ler hızla teknik borca dönüşür.

API Gateway, Service Discovery ve güvenlik
Gateway ile tek giriş noktası ve çapraz kesen ihtiyaçlar
Birden fazla servisi doğrudan istemciye açmak; kimlik doğrulama, rate limit, caching, request shaping ve versiyonlama gibi konuları dağıtır ve karmaşıklaştırır. API Gateway deseni, bu çapraz kesen ihtiyaçları tek noktada toplar. .NET tarafında YARP gibi çözümlerle reverse proxy ve yönlendirme senaryoları güçlü biçimde yönetilebilir.
Service discovery ve yapılandırma yönetimi
Konteyner ortamlarında servis adresleri dinamikleşir. Bu nedenle service discovery (örn. Kubernetes DNS/Service, Consul) ve yapılandırma yönetimi (config/secret) standart bir ihtiyaçtır. Özellikle bağlantı dizeleri, broker endpoint’leri ve feature flag’ler; çevreye göre değişen ama sürülebilir şekilde yönetilmesi gereken yapı taşlarıdır.
Gözlemlenebilirlik: Logging, Metrics, Tracing ve OpenTelemetry
Dağıtık iz sürme ile uçtan uca görünürlük
Microservices’e geçişin en yaygın “acı sürprizi”, sorun olduğunda nerede olduğunun bulunamamasıdır. Bu yüzden logging tek başına yetmez; distributed tracing ile bir isteğin servisler arası yolculuğunu takip etmek gerekir. OpenTelemetry, izleme standartlarını birleştirerek trace/metric/log toplama süreçlerini daha tutarlı hale getirir.
İyi bir gözlemlenebilirlik kurgusu; korelasyon kimliği (trace id), anlamlı log seviyeleri, metrik adlandırma disiplini ve alarm eşiklerini kapsar. Ayrıca “başarısızlık oranı” kadar “gecikme dağılımı” (p95/p99) takibi de önemlidir; çünkü kullanıcı deneyimi çoğu zaman uç değerlerde bozulur.
Pratik bir başlangıç planı: Hangi deseni ne zaman kullanmalı?
Microservices’e geçişte en sağlıklı yaklaşım, tek hamlede parçalamak yerine kontrollü bir evrimdir. Aşağıdaki yol haritası, iletişim ve dayanıklılık desenlerini aşamalı kurgulamanıza yardımcı olur:
- Servis sınırlarını netleştirin; veri sahipliğini belirleyin.
- Senkron çağrılarda timeout/retry/circuit breaker standartlarını tanımlayın.
- Kritik akışlarda asenkron event-driven kurguyu devreye alın.
- Outbox + idempotency ile güvenilir mesaj yayınlama/işleme sağlayın.
- OpenTelemetry ile uçtan uca iz sürme ve metrik toplama başlatın.
Bu adımlar, “dağıtık sistem karmaşası”nı yönetilebilir hale getirir. Daha derin örnekler, uygulama kalıpları ve üretim pratikleri için .NET Microservices Eğitimi sayfasına göz atabilirsiniz.
Özetle: Microservices bir hedef değil, belirli ölçek ve organizasyon ihtiyaçlarında değer üreten bir araçtır. Doğru iletişim modeli (REST/gRPC), doğru mesajlaşma kurgusu (event-driven) ve doğru dayanıklılık desenleri (Polly, circuit breaker, outbox) ile .NET üzerinde sürdürülebilir bir mikro mimari kurmak mümkündür.


