Database Engineering

Boşluğu Kapatmak: Olay Kaydedilen Sistemler için Veri Modelleme Stratejileri

Dağıtık sistemler dünyasında, Olay Kaydetme (Event Sourcing), zaman tutarlılığı ve denetlenebilirlik elde etmek için güçlü bir paradigmaya dönüşmüştür. Durum değişikliklerini değiştirilemez bir olay dizisi olarak ele alarak, organizasyonlar uygulama durumunu herhangi bir zamanda yeniden oluşturabilir. Ancak bu yaklaşım, veri modelleme konusunda benzersiz bir dizi zorluk ortaya çıkarır. Temel gerilim, olay deposu için gerekli olan sıkı normalizasyon ile yoğun okuma sorgularının performans gereksinimleri arasında yer alır. Bu dengeyi başarıyla yönetmek, sağlam bir mimarinin temel işaretidir.

Normalizasyon Temeli: Olay Deposunun Optimize Edilmesi

Olay Kaydetme'nin kalbinde, gerçekleşen her şeyi kaydeden özel bir günlük olan olay deposu yer alır. Burada veri modelleme stratejisi, değiştirilemezliği, atomikliği ve sıkı normalizasyonu önceliklendirmelidir. Okumaları hızlandırmak için bazen normalizasyonu bozabileceğimiz geleneksel ilişkisel veritabanlarının aksine, olay deposu yüksek derecede normalleştirilmiş kalmalıdır.

Neden? Çünkü olay deposu tek doğru kaynaktır. Fazladan veri veya karmaşık ilişkiler sokmak, olaylar yeniden oynatılırken tutarlılık sorunlarına yol açabilir. Bir olayın şeması, o anda gerçekleşen durum değişikliğini tanımlamak için gerekli olan verileri içeren düz bir yapıda olmalıdır. Örneğin, bir UserCreated (Kullanıcı Oluşturuldu) olayını kaydederken, daha sonra değişebilecek ayrı bir profil tablosuna katmak yerine, yalnızca kullanıcı kimliği, e-posta ve zaman damgasını içermelidir.

Aşağıda, temiz ve normalleştirilmiş bir yapıyı vurgulayan bir olay yüklemesi için örnek bir yalancı model bulunmaktadır:


{
  "eventId": "evt-12345-abc",
  "aggregateId": "order-9876",
  "eventType": "OrderCreated",
  "timestamp": "2023-10-27T10:00:00Z",
  "payload": {
    "orderId": "order-9876",
    "customerId": "cust-555",
    "currency": "USD",
    "totalAmount": 150.00
  }
}

Bu yapı, olay günlüğünün doğrulanması ve yeniden oynatılması kolay olan, doğrusal ve sadece ekleme yapılabilen bir dizi olarak kalmasını sağlar. Normalizasyon burada, tek bir mantıksal değişikliğin birden fazla, potansiyel olarak tutarsız tabloyu güncellemeyi gerektirdiği "yazma büyümesi" (write amplification) sorununu önler.

Okuma Tarafı: Normalizasyonu Bozmayı Benimsemek

Olay deposu normalizasyondan güç alırken, uygulama sorgularının dünyası böyle değildir. Olay kaydetme neredeyse her zaman CQRS (Komut Sorumluluk Ayrımı) ile birlikte kullanılır. Sorgu tarafı veya "okuma modeli", belirli kullanım durumları için performansı optimize etmek için var olur. İşte normalizasyonu bozmanın (denormalization) sadece kabul edilebilir değil, zorunlu olduğu yer burasıdır.

Okuma verilerini normalizasyonunu bozmak, sistemin pahalı birleştirme işlemlerinden kaçınmak için bilgileri önceden birleştirmesini sağlar. Ham olayları birleştirerek bir kullanıcının sipariş geçmişini yeniden oluşturmak yerine, bir projeksiyon (okuma modeli), gerekli tüm sipariş detaylarını içeren düz bir yapıyı somutlaştırabilir. Bu dönüşüm süreci, projeksiyon veya somutlaştırma olarak bilinir ve yeni olaylar depoya eklendikçe eşzamansız olarak gerçekleşir.

Tipik bir projeksiyon stratejisi, belirli bir kullanıcı arayüzü veya API uç noktası için gereken verileri yansıtan bir görünüm oluşturmayı içerir. Bir dashboard, müşteri adları ve toplam değerlerle son siparişlerin listesini gerektiriyorsa, projeksiyon servisi OrderCreated (Sipariş Oluşturuldu), OrderStatusChanged (Sipariş Durumu Değişti) ve CustomerUpdated (Müşteri Güncellendi) olaylarını tüketerek önceden hesaplanmış bir JSON belgesi veya geniş bir ilişkisel tablo oluşturur.

Projeksiyonlar Oluşturmak: Dünyalar Arasındaki Köprü

Normalleştirilmiş olay deposunu normalizasyonu bozulmuş okuma görünümlerine bağlayan mekanizma, projeksiyon işleyicisidir. Bu işleyiciler, olay akışlarını belirli veri modellerine dönüştüren tekdüre (idempotent) işlevlerdir. Bu işleyicilerin tasarımı, sistemin esnekliğini belirler.

Bu projeksiyonları tasarlarken, geliştiriciler erişim desenlerine göre farklı stratejileri göz önünde bulundurmalıdır. Basit aramalar için "tek-tablo" projeksiyonu yeterli olabilirken, karmaşık analizler için "çok-tablo" yaklaşımı gerekebilir. Anahtar nokta, projeksiyon mantığının alan mantığından ayrı olması ve okuma şemasının temel olay tanımlarından bağımsız olarak evrimleşebilmesidir.

Aşağıda, bir projeksiyon işleyicisinin bir olayı işleyerek okuma-odaklı bir görünümü nasıl güncelleyebileceğine dair kavramsal bir örnek bulunmaktadır:


function handleOrderCreated(event) {
  const { aggregateId, payload } = event;
  
  // Mevcut okuma modelini getirin (veya yeni birini başlatın)
  let readModel = readModels.get(aggregateId);
  
  if (!readModel) {
    readModel = {
      orderId: aggregateId,
      status: 'CREATED',
      items: [],
      total: 0,
      customerInfo: {} // Hızlı erişim için önceden birleştirilmiş veri
    };
  }

  // Olay durumunu okuma modeline uygulayın
  readModel.status = 'CREATED';
  readModel.total = payload.totalAmount;
  
  // Optimize edilmiş görünümü saklayın
  readModels.set(aggregateId, readModel);
}

Sonuç: Denge Sanatı

Olay kaydedilen sistemlerde normalizasyon ve okuma-odaklı görünümler arasındaki denge, statik bir karar değil, sürekli bir mimari dansıdır. Olay deposu, veri bütünlüğünü garanti altına almak için katı ve normalleştirilmiş bir gerçeklik olarak kalmalı, okuma modelleri ise hız ve belirli kullanıcı ihtiyaçları için tasarlanmış esnek, normalizasyonu bozulmuş nesneler olmalıdır.

Bu kaygıları sıkı bir şekilde ayırarak ve CQRS'den yararlanarak, geliştiriciler hem veri bozulmasına karşı dayanıklı hem de yoğun yük altında performanslı bir sistem elde edebilirler. Alınan temel ders, verileri yazma ve okuma için farklı şekilde modellemektir. Olay akışının karmaşılığını, basit, hızlı ve güvenilir sorgu arayüzlerini güçlendirmek için benimseyin. Bunu yaparak, olay kaydetmenin gerçek potansiyelini ortaya çıkarır ve teorik bir deseni, pratik, yüksek ölçekli bir mühendislik çözümüne dönüştürürsünüz.

Share: