Database Engineering

Denetlenebilir Yüksek İşlem Hacimli Sistemler Oluşturma: PostgreSQL ile Olay Kaynağı ve CQRS

Modern yazılım mühendisliğinde, yüksek işlem hacmini sıkı denetim uyumluluğuyla dengeleme baskısı kesintisizdir. Finansal uygulamalar, sağlık platformları ve envanter yönetim sistemleri genellikle iki katı bir gereksinimle karşı karşıyadır: saniyede milyonlarca işlemi işlerken her durum değişikliğinin değişmez ve hileye dayanıklı bir geçmişini korumaları gerekir. Geleneksel CRUD (Oluştur, Oku, Güncelle, Sil) mimarileri, bu iki gereksinimi aynı anda karşılamada genellikle zorlanır; bu da performans darboğazlarına ve karmaşık mutabakat mantıklarına yol açar.

Bu noktada Komut Sorgu Sorumluluk Ayrımı (CQRS) ve Olay Kaynağı (Event Sourcing) kombinasyonu öne çıkar. PostgreSQL gibi sağlam bir ilişkisel veritabanı motoruyla doğru şekilde uygulandığında, ağır yük altında yalnızca performanslı değil, aynı zamanda yasal düzenlemelere doğası gereği uyumlu olan bir sistem elde edebilirsiniz. Bu yazı, bu tür sistemleri oluşturmak için mimari desenleri, veritabanı tasarım stratejilerini ve pratik uygulama detaylarını incelemektedir.

Temel Desenleri Anlamak

Olay Kaynağı, verinin saklanma şeklindeki temel yaklaşımı değiştirir. Bir varlığın (örneğin durumu "Sevk Edildi" olan bir Sipariş) mevcut durumunu saklamak yerine, o duruma ulaşan değişmez olayların bir dizisini saklarsınız (örneğin "SiparişOluşturuldu", "Ödemeİşlendi", "ÜrünSevkEdildi"). Mevcut durumu almak için bu olaylar yeniden oynatılır. Bu yaklaşım, tanım gereği eksiksiz bir denetim izi sağlar.

CQRS, yazma modelini okuma modelinden ayırır. Olay Kaynağı'nda yazma işlemleri pahalıdır çünkü bunlar, yalnızca ekleme yapılabilen bir günlüğe ekleme yapmayı ve potansiyel olarak projeksiyonları güncellemeyi içerir. Okuma işlemleri ise sorgu performansı için optimize edilmelidir. Bu endişeleri birbirinden ayırarak, okuma yedeklerinizi yazma sunucularınızdan bağımsız olarak ölçeklendirebilir ve sorgu karmaşıklığından bağımsız olarak yüksek işlem hacmini garanti edebilirsiniz.

Olay Akışları İçin PostgreSQL Tasarımı

PostgreSQL, ACID uyumluluğu, güçlü JSONB desteği ve mükemmel eşzamanlılık kontrolü nedeniyle Olay Kaynağı için mükemmel bir seçenektir. Olay deposunun temel tablosu genellikle yalnızca ekleme yapılabilen bir günlüktür. Aşağıda, yazma performansını ve veri bütünlüğünü önceliklendiren bir şema tanımı bulunmaktadır.

CREATE TABLE event_store (
    id BIGSERIAL PRIMARY KEY,
    aggregate_id UUID NOT NULL,
    event_type VARCHAR(100) NOT NULL,
    payload JSONB NOT NULL,
    version INTEGER NOT NULL,
    occurred_at TIMESTAMPTZ DEFAULT NOW()
);

-- İndeksler performans için kritik öneme sahiptir
CREATE INDEX idx_event_aggregate ON event_store (aggregate_id, version);
CREATE INDEX idx_event_occurred ON event_store (occurred_at DESC);

version sütununa dikkat edin. Bu, iyimser eşzamanlılık kontrolü için gereklidir. Bir olay yazarken uygulama, varlığın mevcut sürümünün beklenen sürümle eşleşip eşleşmediğini kontrol eder. Eşleşiyorsa olay eklenir ve sürüm artırılır. Eşleşmiyorsa bir çakışma oluşur ve yazma işlemi başarısız olur; bu da yarış durumlarını önler.

Iyimser Eşzamanlılık Kontrolünün Uygulanması

Yüksek işlem hacmi, verimli kilitleme mekanizmaları gerektirir. Satır düzeyindeki kilitler yazmaları sıralayabileceğinden, Olay Kaynağı iyimser eşzamanlılıktan yararlanır. PostgreSQL'de PL/pgSQL kullanarak transactional bir yazma işleminin nasıl uygulanacağı aşağıdadır.

CREATE OR REPLACE FUNCTION append_event(
    p_aggregate_id UUID,
    p_event_type VARCHAR,
    p_payload JSONB,
    p_expected_version INTEGER
) RETURNS BIGINT AS $$
DECLARE
    v_new_version INTEGER;
    v_row_count INTEGER;
BEGIN
    -- Varlığın varlığını kontrol et ve sürümü doğrula
    SELECT version INTO v_new_version
    FROM event_store
    WHERE aggregate_id = p_aggregate_id
    ORDER BY version DESC
    LIMIT 1;

    IF v_new_version IS NULL THEN
        v_new_version := 0;
    END IF;

    IF v_new_version != p_expected_version THEN
        RAISE EXCEPTION 'Eşzamanlılık çakışması: beklenen sürüm % ancak bulunan %', 
                        p_expected_version, v_new_version;
    END IF;

    -- Yeni olayı ekle
    INSERT INTO event_store (aggregate_id, event_type, payload, version)
    VALUES (p_aggregate_id, p_event_type, p_payload, v_new_version + 1);

    RETURN v_new_version + 1;
END;
$$ LANGUAGE plpgsql;

Yüksek Performanslı Okumalar İçin Projeksiyonlar

Ham olay akışından okuma işlemi işlem açısından pahalı olduğundan, CQRS okuma işlemleri için ayrı projeksiyonlar (veya matikleştirilmiş görünümler) tutmamızı emreder. Bu projeksiyonlar, olaylar işlenirken eşzamansız veya eşzamanlı olarak güncellenir. Örneğin, tüm siparişlerin geçmişini yeniden oynatmadan, müşteri veya tarihe göre hızlı sorgulara olanak tanıyan normalleştirilmemiş bir orders_summary tablosu tutabilirsiniz.

Denetim uyumluluğunu sağlamak için olay deposu gerçeklik kaynağı olarak kalır. Projeksiyonlar türetilmiş verilerdir. Bir tutarsızlık bulunursa, herhangi bir projeksiyonu değişmez olay akışından yeniden oluşturabilirsiniz; bu da toplam tutarlılığı garanti eder.

Sonuç

PostgreSQL ile Olay Kaynağı ve CQRS uygulamak sihirli bir çözüm değildir; uygulama mantığı ve nihai tutarlılık yönetimi açısından karmaşıklık getirir. Ancak yüksek işlem hacmi ve sıkı denetim izleri gerektiren sistemler için üstün bir mimari temel sunar. PostgreSQL'in eşzamanlılık kontrolü ve JSONB depolama için sağlam özelliklerinden yararlanarak geliştiriciler hem ölçeklenebilir hem de uyumlu sistemler oluşturabilir. Anahtar, projeksiyonlarınızı dikkatli bir şekilde tasarlamak ve okuma tarafını, yazma tarafında saklanan değişmez geçmişle senkronize tutmak için sağlam olay işleyicilerine yatırım yapmaktır.

Share: