Sql & Veritabanı İle Uygulamalar İçin Veri Paylaşımlı Mimari Nasıl Yapılır?

Sql & Veritabanı İle Uygulamalar İçin Veri Paylaşımlı Mimari Nasıl Yapılır?
Sql & Veritabanı İle Uygulamalar İçin Veri Paylaşımlı Mimari Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu uygulamalı rehberde, veritabanı yönetim sistemi olarak PostgreSQL 17 ve uygulama katmanı olarak modern bir Node.js (TypeScript) ortamı kullanacağız. Veri paylaşımını yönetmek için "Schema-based" (şema tabanlı) izolasyon yöntemini tercih edeceğiz.

  • PostgreSQL 17+: Veritabanı yönetim sistemi.
  • Node.js 22+: Uygulama çalışma zamanı.
  • Prisma ORM: Veritabanı şeması ve veri erişim katmanı.
  • Docker: Yerel geliştirme ortamını izole etmek için.

Başlamadan önce sisteminizde docker-compose aracının yüklü olduğundan emin olun. Veritabanı bağlantı dizgelerinizi (connection strings) asla kod içerisinde açık metin olarak tutmayın, her zaman .env dosyalarını kullanın.

Adım 1: Veritabanı Şemasını Tasarlama

Veri paylaşımlı mimarinin temelinde, verilerin hangi uygulamalar tarafından paylaşıldığını belirleyen bir "Master Schema" yapısı yatar. Öncelikle, farklı servislerin ortak erişebileceği bir tablo yapısı oluşturalım.

-- Ortak veri şeması oluşturma
CREATE SCHEMA shared_data;

CREATE TABLE shared_data.users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) UNIQUE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

Bu SQL kodu, tüm mikroservislerin erişebileceği merkezi bir kullanıcı tablosu oluşturur. UUID kullanımı, farklı sistemlerin veri çakışması yaşamadan kayıt oluşturmasını sağlar.

Adım 2: Uygulama Katmanında Veri Erişimini Yapılandırma

Uygulama katmanında, veritabanına doğrudan sorgu atmak yerine, paylaşımlı veriye erişimi yöneten bir "Data Access Layer" (Veri Erişim Katmanı) oluşturmalıyız. Bu, SQL injection riskini ortadan kaldırır.

// Prisma client ile güvenli veri çekme
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function getUserById(userId: string) {
    // Parametreli sorgu kullanarak SQL Injection önlenir
    return await prisma.users.findUnique({
        where: { id: userId }
    });
}

Burada Prisma ORM kullanarak SQL Injection'a karşı koruma sağlıyoruz. findUnique metodu, veritabanı sürücüsü tarafından otomatik olarak parametreleştirilir.

Adım 3: Veri Paylaşımında İzolasyon ve Güvenlik

Birden fazla uygulama aynı veritabanını kullandığında, her uygulamanın sadece yetkili olduğu verilere erişmesi gerekir. PostgreSQL'de "Row Level Security" (Satır Düzeyinde Güvenlik - RLS) kullanarak bunu sağlayabiliriz.

-- RLS aktif etme
ALTER TABLE shared_data.users ENABLE ROW LEVEL SECURITY;

-- Sadece belirli bir role sahip olanların okumasına izin ver
CREATE POLICY user_access_policy ON shared_data.users
    FOR SELECT
    USING (current_user = 'app_service_role');

RLS, veritabanı seviyesinde bir güvenlik katmanı oluşturur. Uygulama kodunuzda bir hata olsa bile, veritabanı kullanıcısının yetkisi dışındaki verilere erişim engellenir.

Adım 4: Performans İzleme ve Optimizasyon

Veri paylaşımlı mimarilerde en büyük sorun, birden fazla servisin aynı tabloya yüklenmesiyle oluşan performans darboğazlarıdır. İndeksleme stratejisi bu noktada hayat kurtarır.

-- Sık sorgulanan alanlar için indeks oluşturma
CREATE INDEX idx_users_email ON shared_data.users(email);

İndeksler, veritabanı sorgularının çalışma süresini milisaniyelere indirir. Ancak, çok fazla indeksin yazma (INSERT/UPDATE) işlemlerini yavaşlatacağını unutmayın.

Adım 5: Yöntemlerin Karşılaştırılması

Veri paylaşımı için kullanılan farklı mimari yaklaşımlarını aşağıdaki tabloda özetledik:

Yöntem Avantaj Dezavantaj
Shared Database Basitlik, veri tutarlılığı Tek hata noktası (SPOF)
Database per Service Yüksek izolasyon Veri senkronizasyonu zor
Schema-based Sharing Dengeli yönetim Karmaşık yetkilendirme

Adım 6: Hata Yönetimi ve Debugging

Paylaşımlı mimarilerde en yaygın hata "Deadlock" (kilitlenme) durumudur. İki servis aynı anda aynı satırı güncellemeye çalıştığında veritabanı kilitlenir. Bunu engellemek için işlem (transaction) yönetimini doğru yapmalısınız.

// Transaction ile güvenli güncelleme
await prisma.$transaction(async (tx) => {
    const user = await tx.users.update({
        where: { id: '123' },
        data: { email: 'yeni@email.com' }
    });
    return user;
});

$transaction kullanımı, işlem başarılı olursa tüm verilerin kaydedilmesini, aksi halde geri alınmasını (rollback) garanti eder.

Güvenlik Uyarısı: Veritabanı bağlantı bilgilerinizi ve yönetici parolalarınızı asla uygulama kaynak koduna gömmeyin. Üretim ortamında her zaman AWS Secrets Manager veya HashiCorp Vault gibi araçlar kullanarak çevresel değişkenleri güvenli bir şekilde yönetin.

Sıkça Sorulan Sorular

Veri paylaşımlı mimari her proje için uygun mudur?

Hayır, küçük ölçekli projeler için gereksiz karmaşıklık yaratır. Ancak, mikroservis mimarisine geçiş yapan veya veri tutarlılığının kritik olduğu finansal uygulamalar için idealdir.

SQL Injection nasıl kesin olarak engellenir?

Dinamik SQL sorguları oluşturmaktan kaçının. Daima ORM kullanın veya ham SQL yazmanız gerekiyorsa parametreli sorguları (prepared statements) tercih edin.

RLS (Row Level Security) performansı düşürür mü?

Doğru indeksleme yapıldığında RLS'in performans üzerindeki etkisi ihmal edilebilir düzeydedir. Ancak karmaşık politikalar sorgu süresini artırabilir.

Veritabanı kilitlenmelerini nasıl izlerim?

PostgreSQL'in pg_stat_activity görünümünü kullanarak o an çalışan sorguları ve kilitli işlemleri gerçek zamanlı olarak izleyebilirsiniz.

Veri paylaşımı yaparken veritabanı şemasını nasıl güncellerim?

Migration araçlarını kullanın. Prisma Migrate veya Flyway gibi araçlar, şema değişikliklerini versiyonlayarak tüm servislerin uyumlu çalışmasını sağlar.

Veri Paylaşımı Mimarilerinde İleri Seviye İzleme ve Loglama

Veri paylaşımlı mimarilerde, birden fazla servisin aynı veritabanı üzerinde işlem yapması, hata kaynağını bulmayı zorlaştırabilir. Bu nedenle, veritabanı seviyesinde "Audit Log" (Denetim Günlüğü) mekanizması kurmak kritik bir öneme sahiptir. Hangi servisin, hangi satır üzerinde, ne zaman değişiklik yaptığını takip etmek için PostgreSQL üzerinde bir tetikleyici (trigger) yapısı kullanabilirsiniz.

Audit Log İçin Veritabanı Trigger Yapılandırması

Aşağıdaki örnek, orders tablosunda gerçekleşen her değişikliği audit_logs tablosuna kaydeden bir yapıyı göstermektedir:

CREATE TABLE audit_logs (
    id SERIAL PRIMARY KEY,
    table_name TEXT,
    operation TEXT,
    changed_by TEXT,
    changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    old_data JSONB,
    new_data JSONB
);

CREATE OR REPLACE FUNCTION log_changes() RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO audit_logs (table_name, operation, changed_by, old_data, new_data)
    VALUES (TG_TABLE_NAME, TG_OP, current_user, to_jsonb(OLD), to_jsonb(NEW));
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_audit_orders
AFTER INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW EXECUTE FUNCTION log_changes();

Dağıtık Sistemlerde Transaction Yönetimi ve Deadlock Çözümleri

Birden fazla uygulama katmanı aynı veritabanı tablolarına eriştiğinde, "Deadlock" (Kilitlenme) kaçınılmaz bir risk haline gelir. Özellikle yüksek trafikli sistemlerde, transaction sürelerini minimumda tutmak ve veritabanı kilitlenme stratejilerini doğru belirlemek gerekir.

Deadlock Riskini Azaltma Stratejileri

  • Sıralı Erişim: Tabloları her zaman aynı sırada güncelleyin (Örn: Önce users, sonra orders).
  • Kısa Transactionlar: Veritabanı üzerinde uzun süren hesaplamalar yapmayın; hesaplamaları uygulama katmanında yapıp sonucu veritabanına tek seferde yazın.
  • Lock Timeout Ayarı: Bekleme süresini sınırlayarak sistemin kilitlenmesini engelleyin.

Uygulama seviyesinde, özellikle PostgreSQL kullanıyorsanız, kilitlenme süresini aşağıdaki komutla sınırlandırabilirsiniz:

-- Mevcut oturum için kilitlenme süresini 5 saniye ile sınırla
SET lock_timeout = '5s';

-- Transaction bloğu
BEGIN;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 101;
-- İşlemler...
COMMIT;

Bu yapı, sisteminizde bir servis veritabanını kilitlediğinde diğer servislerin sonsuza kadar beklemesini engeller ve uygulamanızın hata mesajı döndürerek kullanıcıyı bilgilendirmesine olanak tanır.

Sonuç

Sql & veritabanı ile uygulamalar için veri paylaşımlı mimari kurmak, disiplinli bir veritabanı tasarımı ve güvenlik bilinci gerektirir. Bu rehberde öğrendiğiniz RLS kullanımı, transaction yönetimi ve indeksleme stratejileri, sisteminizin hem güvenli hem de performanslı kalmasını sağlayacaktır. Bir sonraki adım olarak, veritabanı üzerinde "Read Replica" (Okuma Kopyası) kurarak yükü dağıtmayı ve sistemin ölçeklenebilirliğini daha da artırmayı deneyebilirsiniz.

Yasal Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamına almadan önce kendi güvenlik testlerinizi yapmanız ve veritabanı yedekleme stratejilerinizi oluşturmanız sorumluluğunuzdadır.

Bu yazıya tepkinizi paylaşın:
Selin Yılmaz

Kullanıcı odaklı rehberler hazırlama konusunda uzmanım. Adım adım anlatımlarla karmaşık süreçleri herkes için anlaşılır kılıyorum.

Yorumlar (0)

Yorum Yaz