Merhaba,
Mikroservis mimarisi, günümüzde büyük ölçekli yazılım sistemlerinin inşa edilmesinde yaygın olarak kullanılan bir yaklaşımdır. Bu yapıda, her bir işlevsel alan (örneğin ödeme, sipariş, stok yönetimi gibi) kendi bağımsız servisinde çalışır ve birbirinden bağımsız ama iletişim halinde olarak bir bütün oluşturur. Ancak, mikroservislerin bu yapısı, veritabanı yönetimi ve işlem yönetimi gibi konularda bazı zorluklar yaratabilir. Bu yazıda, mikroservisler arasındaki işlem yönetimini daha iyi anlayabilmek için karşılaşılan problemleri ve bunlara yönelik çözümleri açıklayacağım.
Mikroservislerin Çalışma Prensibi
Mikroservisler, bağımsız olarak çalışabilen küçük, bir işlevi yerine getiren servislerdir. Bu servisler arası iletişim, genellikle API'ler aracılığıyla sağlanır. Örneğin, bir kullanıcı sipariş verdiğinde, sipariş servisi ödeme bilgilerini kontrol eder ve ardından ödeme servisi işlem yapar. Aynı anda, stok servisi de stok seviyesini günceller. Tüm bu işlemler, kullanıcı tarafından fark edilmeden, arka planda gerçekleştirilir.
Potansiyel Sorun
Mikroservislerin bağımsız olarak çalışması, bazı zorlukları da beraberinde getirir. En büyük sorunlardan biri, veri tutarlılığıdır. Her mikroservisin kendi veritabanına sahip olması, işlemler arası tutarlılığın sağlanmasını zorlaştırabilir. Bu, özellikle veritabanları arasında tutarsızlık oluşmasına yol açabilir. Atomicity (atomiklik) ve consistency (tutarlılık) gibi veritabanı özelliklerinin sağlanması, mikroservislerde zordur. Ayrıca, hata durumunda tüm sistemin tutarlı bir şekilde geri alınması (rollback) karmaşık hale gelebilir.
Hata Durumu
Örneğin, ödeme işlemi başarılı olmasına rağmen stok seviyesi güncellenmediğinde, sistem kullanıcıya siparişi teslim etmiş gibi görünebilir. Ancak, diğer mikroservislerde hâlâ eski veriler bulunuyor olabilir. Bu tür hataların önüne geçmek için, mikroservisler arasında bir transaction yönetimi çözümüne ihtiyaç vardır.
Çözüm Yöntemleri
Bu tür sorunların üstesinden gelebilmek için birkaç çözüm önerisi bulunmaktadır. Bu çözümler, mikroservisler arası tutarlılığı sağlamak ve işlemlerin düzgün bir şekilde yönetilmesini sağlamak için kullanılır.
1. Saga Pattern
Saga Pattern, mikroservisler arası uzun süreli ve dağılmış işlemleri yönetmek için kullanılan bir yöntemdir. Bu desen, bir işlem bir dizi adımdan oluştuğunda, her adımda bir event yayınlanarak diğer mikroservisler bilgilendirilir. Eğer bir işlem başarısız olursa, geri alma işlemleri (compensating transactions) tetiklenir ve önceki adımlar geri alınır.
Örneğin, ödeme işlemi başarısız olursa, ödeme servisi bu durumu bildirir ve diğer servislere yapılan işlemleri geri almasını söyler.
public class PaymentService : ITransactionHandler
{
public async Task HandlePaymentAsync(PaymentRequest request)
{
var paymentResult = await ProcessPaymentAsync(request);
if (!paymentResult.Success)
{
await CompensatePaymentAsync(request);
throw new Exception("Ödeme Alınamadı");
}
await _eventBus.PublishAsync(new PaymentProcessedEvent(request.OrderId));
}
}
public async Task CompensatePaymentAsync(PaymentRequest request)
{
// Geri alınacak işlemler.
}
Bu yapı, işlemler arasındaki tutarlılığı koruyarak hata durumunda önceki adımların geri alınmasını sağlar.
Saga Pattern : https://sinantosun.com/blog-detayi/saga-pattern-nedir
2. Event-Driven Yaklaşımı
Event-Drivenyaklaşımı, mikroservislerin birbirine bağımsız çalışırken, bir işlem gerçekleştikten sonra event (olay) yayınlanarak diğer mikroservislere bildirilmesini sağlar. Bu sayede, her mikroservis kendi işlevini yerine getirirken, sistemin genel akışı da sağlanmış olur. Eventlerin işlenmesi asenkron olduğu için, işlemler zaman içinde tamamlanabilir ve sistemin tutarlılığı korunabilir.
public class OrderService
{
private readonly IEventBus _eventBus;
public async Task PlaceOrder(Order order)
{
try
{
await _repository.SaveAsync(order);
await _eventBus.PublishAsync(new OrderCreatedEvent(order.Id));
}
catch (Exception ex)
{
// Hata yönetimi
}
}
}
Bu yaklaşımda, her mikroservis bir event (olay) yayınlar ve diğer mikroservisler bu eventleri dinleyerek işlemi tamamlar.
3. Eventual Consistency
Mikroservisler arasındaki işlemler hemen tamamlanmayabilir. Eventual Consistency, sistemin zaman içinde tutarlı hale gelmesini sağlayan bir yaklaşımdır. Yani, mikroservisler anında tam olarak senkronize olmayabilir, ancak zamanla tüm sistem tutarlı hale gelir.
4. MediatR ile Transaction Yönetimi
MediatR, farklı işlemler arasında bağımlılıkları yönetmek için kullanılan bir araçtır. Bir işlem sırasındaki adımlar, command ve handler yapılarıyla düzenlenir. Her bir işlem için bir command handler yazılır ve bu handler'lar, işlem sırasındaki bağımlılıkları düzgün bir şekilde yönetir.
public class CreateOrderCommand : IRequest
{
public Order Order { get; set; }
}
public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand>
{
private readonly IOrderRepository _orderRepository;
private readonly IPaymentService _paymentService;
public async Task<Unit> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
var paymentResult = await _paymentService.ProcessPaymentAsync(request.Order);
if (!paymentResult.Success)
throw new Exception("Ödeme Alınamadı");
await _orderRepository.SaveAsync(request.Order);
return Unit.Value;
}
}
MediatR, işlem sırasındaki bağımlılıkları yöneterek, işlemlerin doğru sırayla gerçekleştirilmesini sağlar.
5 .Transactional Outbox Pattern
Bu desen, mikroservisler arasında event-driven iletişim kullanıldığında, eventlerin güvenli bir şekilde gönderilmesini sağlar. Mikroservis her işlem sırasında, işlemin kaydını ve eventleri aynı anda bir outbox tablosuna kaydeder. Bu şekilde, işlem başarıyla tamamlandıktan sonra eventler güvenli bir şekilde yayınlanabilir.
Sonuç
Mikroservis mimarisi, dağıtık ve bağımsız olarak çalışan servislerle büyük sistemlerin inşa edilmesini sağlar. Ancak, veri tutarlılığı, transaction yönetimi ve hata yönetimi gibi konular, bu mimarinin zorluklarından bazılarıdır. Saga Pattern, Event-Driven Yaklaşım, Eventual Consistencyv e MediatR gibi çözümler, bu tür zorluklarla başa çıkmak için etkili yöntemler sunar. Bu yöntemler, mikroservisler arasındaki işlemleri koordine ederek, tutarlı bir sistemin inşa edilmesini sağlar ve hata durumunda geri almayı mümkün kılar.
Görüşmek üzere! 👋