Dağıtık sistem tasarımında, geleneksel CRUD (Oluştur, Oku, Güncelle, Sil) modeli sıkça başlangıç noktası olarak hizmet verir. Ancak uygulamalar karmaşıklık ve ölçek açısından büyüdükçe, monolitik bir veritabanı katmanı darboğaza dönüşebilir. İşte burada Komut Sorgu Sorumluluk Ayrımı (CQRS) devreye girer. Greg Young ve Eric Evans tarafından popüler hale getirilen bu mimari desen, okuma ve yazma işlemlerinin sorumluluklarını ayırarak sistemlerin bağımsız olarak ölçeklenmesine ve belirli işlemler için optimize edilmesine olanak tanıyan sağlam bir çözüm sunar.
Temel Kavram: Neden Ayırmalıyız?
CQRS'nin kalbinde basit bir ilke yatar: komutlar ve sorgular farklı özelliklere sahiptir. Bir Komut, sistemin durumunu değiştirir (örneğin, sipariş verme), ancak bir Sorgu, yan etkiler olmadan bilgiyi getirir (örneğin, sipariş geçmişini görüntüleme). Standart bir ilişkisel veritabanında bu işlemler genellikle aynı kaynaklar için rekabet eder, bu da çakışmalara ve performans sorunlarına yol açar.
Bu işlemleri ayırarak CQRS, okuma ve yazma için farklı veri modelleri kullanmanıza olanak tanır. İşlemleri yönetmek için (Yazma Modeli) yüksek derecede normalize edilmiş, ACID uyumlu bir ilişkisel veritabanına ve raporları görüntülemek için (Okuma Modeli) normalize edilmemiş, okuma için optimize edilmiş bir NoSQL veritabanına veya veri ambarına sahip olabilirsiniz.
CQRS'nin Temel Faydaları
CQRS'yi benimsemek her soruna çözüm sunmaz, ancak belirli senaryolarda belirgin avantajlar sağlar:
- Ölçeklenebilirlik: Yükü temel alarak okuma kopyalarınızı ve yazma sunucularınızı bağımsız olarak ölçeklendirebilirsiniz.
- Güvenlik: Erişim kontrolü daha ayrıntılı hale getirilebilir. Bir hizmet, kullanıcı profillerini güncelleme iznine sahip olabilir ancak silme iznine sahip olmayabilir.
- Basitlik: Yazma modeli yalnızca iş mantığı ve bütünlüğe odaklanabilir, okuma modeli ise tamamen sunuma ve performansa odaklanabilir.
- Denetlenebilirlik: CQRS, her değişikliğin değiştirilemez bir olay olarak kaydedildiği ve eksiksiz bir denetim izi sağlayan Olay Kaynağı (Event Sourcing) ile doğal olarak eşleşir.
CQRS'yi Uygulama: Pratik Bir Örnek
Bunun tipik bir .NET veya Java tarzı hizmet mimarisinde nasıl görünebileceğine bakalım. Arayüzün komutlar ve sorgular arasında nasıl net bir ayrım yaptığına dikkat edin.
// Komut Arayüzü (Yazma Modeli)
public interface ICommand {
Guid Id();
}
public class PlaceOrderCommand : ICommand {
private readonly Guid _orderId;
private readonly List<OrderItem> _items;
public PlaceOrderCommand(Guid orderId, List<OrderItem> items) {
_orderId = orderId;
_items = items;
}
public Guid Id() { return _orderId; }
}
// Sorgu Arayüzü (Okuma Modeli)
public interface IQuery<TResult> {
}
public class GetOrderDetailsQuery : IQuery<OrderDetailsDto> {
private readonly Guid _orderId;
public GetOrderDetailsQuery(Guid orderId) {
_orderId = orderId;
}
}
// İşleyici Uygulaması
public class OrderHandler {
// Durum değişikliklerini işler
public void Handle(PlaceOrderCommand command) {
var order = new Order(command.Id(), command.Items());
// Yazma Veritabanına Kaydet
_repository.Save(order);
// Okuma Modelini Güncellemek için Olayı Yayınla
_eventPublisher.Publish(new OrderPlacedEvent(command.Id()));
}
// Veri alımını işler
public OrderDetailsDto Handle(GetOrderDetailsQuery query) {
// Okuma Veritabanından Sorgula (optimize edilmiş görünüm)
return _readRepository.GetOrderDetails(query.OrderId());
}
}
Bu örnekte, komut için Handle yöntemi gerçeklik kaynağıyla etkileşime girer, değişikliği kalıcı hale getirir ve bir olayı tetikler. Bu olay daha sonra normalize edilmemiş okuma veritabanını güncelleyen ayrı bir işlem tarafından tüketilebilir, böylece sorgular için mevcut olan verinin zamanla tutarlı (eventually consistent) olması sağlanır.
Sonuç
CQRS, okumaların ve yazmaların temelde farklı işlemler olduğunu kabul ederek yüksek performanslı, ölçeklenebilir mimariler sağlayan güçlü bir desendir. Veri tutarlılığı ve altyapı yönetimi konusunda karmaşıklık getirse de, büyük ölçekli, veri yoğun uygulamalar için faydaları tartışmasızdır. Muazzam iş yükünü ve karmaşık iş mantığını yönetebilen dayanıklı sistemler inşa etmeyi hedefleyen geliştiriciler için CQRS'yi ustalaşmak, mimari yolculuklarında temel bir adımdır.