sazak@labs:~
oturum

etiketler

NoSQLPostgreSQLSQLData ArchitectureRedispolyglot persistence

Software · Mar 14, 2026 · 11 dk okuma

SQL, NoSQL ve Redis: Kurumsal Sistemlerde Doğru Veri Mimarisi Nasıl Seçilir?

SQL, NoSQL ve Redis birbirinin alternatifi olmak zorunda değil. Doğru veri mimarisi; erişim modelleri, consistency gereksinimleri, veri yaşam döngüsü ve operasyonel maliyet birlikte değerlendirilerek kurulur.

SQL, NoSQL ve Redis: Kurumsal Sistemlerde Doğru Veri Mimarisi Nasıl Seçilir?

Kurumsal bir sistemde doğru veri mimarisi, SQL ile NoSQL arasında seçim yapılarak değil, verinin nasıl yazıldığını, nasıl okunduğunu ve hangi consistency garantileriyle yönetilmesi gerektiğini belirleyerek tasarlanır. PostgreSQL veya MSSQL ana kayıt sistemi olabilir; Redis sık erişilen verileri hızlandırabilir, bir document database değişken veri yapılarını taşıyabilir, Elasticsearch ise arama ihtiyaçlarını karşılayabilir. Bu bileşenlerin birlikte kullanılması ancak her birinin açık bir görevi ve tanımlı bir veri sahipliği sınırı varsa anlamlıdır.

Yanlış kararın maliyeti genellikle ilk geliştirme aşamasında görülmez. Sistem büyüdüğünde cache invalidation problemleri, tutarsız kayıtlar, yavaş sorgular, karmaşık deployment süreçleri ve beklenmedik altyapı maliyetleri ortaya çıkar. Özellikle kurumsal sistemlerde mesele yalnızca performans değildir; bir siparişin hangi durumda olduğu, bir ödemenin gerçekleşip gerçekleşmediği ve hangi kaydın doğru kabul edileceği açık biçimde belirlenmelidir.

Veritabanı seçimini erişim modeli belirler

Bir veritabanını değerlendirmeye başlamadan önce uygulamanın gerçekleştirdiği işlemleri incelemek gerekir. Hangi veri hangi sıklıkla okunuyor? Bir işlem kaç kaydı birlikte değiştiriyor? Sorgular önceden biliniyor mu, yoksa kullanıcılar farklı alanlarda filtreleme yapabiliyor mu? Bu soruların cevapları veritabanı kategorilerinden daha değerlidir.

Burada temel kavram access pattern'dir. Access pattern, uygulamanın veriye hangi anahtarlarla, hangi sorgularla ve hangi sıklıkta eriştiğini ifade eder. Aynı veri kümesi üzerinde çalışan iki uygulama, farklı access pattern nedeniyle farklı mimari çözümlere ihtiyaç duyabilir.

Örneğin bir sipariş yönetim sisteminde sipariş oluşturma, stok düşme ve ödeme durumunu güncelleme işlemleri arasında güçlü ilişkiler vardır. Sipariş geçmişini görüntülemek ise çoğunlukla okuma işlemidir. Ürün açıklamalarında serbest metin araması yapmak bambaşka bir erişim modelidir. Bu üç işlemi aynı veritabanı üzerinden gerçekleştirmek mümkündür, ancak her birini aynı mekanizmayla çözmek zorunlu değildir.

Read-heavy workload, okuma işlemlerinin baskın olduğu iş yükünü ifade eder. Ürün katalogları, raporlama ekranları ve sık görüntülenen referans veriler buna örnek olabilir. Write-heavy workload ise sürekli kayıt oluşturulan veya güncellenen sistemlerde görülür. İşlem kayıtları, telemetri akışları ve yoğun olay toplama sistemleri bu gruba girebilir.

Ancak read-heavy ve write-heavy ayrımı yalnızca işlem sayısından ibaret değildir. Bir milyon küçük key-value okuması ile karmaşık JOIN içeren bir sorgu aynı maliyete sahip değildir. Benzer şekilde tek satırlık bir INSERT ile birden fazla tabloyu güncelleyen transaction farklı kaynaklar tüketir.

Bu nedenle kapasite planlamasında sorgu sayısının yanında veri boyutu, indeks kullanımı, eşzamanlı bağlantı sayısı, transaction süresi ve kabul edilebilir latency değerlendirilmelidir. Ortalama latency tek başına yeterli değildir; p95 veya p99 gibi yüksek yüzdeliklerdeki gecikmeler, kullanıcıların yoğun saatlerde karşılaşacağı davranışı daha iyi gösterir.

Relational model ile NoSQL arasındaki fark yanlış anlatılıyor

Popüler açıklama SQL veritabanlarının ilişkisel ve katı, NoSQL sistemlerinin ise esnek ve hızlı olduğunu söyler. Bu yaklaşım temel mekanizmayı kaçırır: Fark yalnızca verinin nasıl saklandığında değil, ilişkilerin, transaction sınırlarının ve sorgu maliyetlerinin nasıl yönetildiğindedir.

Relational model, veriyi relation adı verilen mantıksal yapılarda temsil eder. Uygulamada bunlar çoğunlukla tablolar olarak görülür. Primary key kayıtları tanımlar, foreign key tablolar arasındaki referans bütünlüğünü korur, constraint ise geçersiz durumların veritabanına yazılmasını engelleyebilir.

PostgreSQL ve Microsoft SQL Server, yani MSSQL, bu yaklaşımın kurumsal sistemlerde yaygın kullanılan örnekleridir. Her ikisi de transaction, indeksleme, JOIN, concurrency control ve kapsamlı sorgulama özellikleri sunar. PostgreSQL'in JSONB desteği ve MSSQL'in JSON işleme özellikleri de ilişkisel veritabanlarının yalnızca sabit kolonlardan oluşan basit yapılar olmadığını gösterir.

Örneğin bir sipariş kaydının mevcut olmayan bir müşteriye bağlanmasını foreign key ile engelleyebilirsiniz. Sipariş oluşturma ve stok rezervasyonu aynı transaction içinde gerçekleşiyorsa, işlem başarısız olduğunda yapılan değişikliklerin birlikte geri alınmasını sağlayabilirsiniz. Bu garanti uygulama kodunun her noktada doğru davranmasına bırakılmaz.

Document database ise çoğunlukla JSON benzeri document yapıları üzerinde çalışır. MongoDB bu yaklaşımın bilinen örneklerinden biridir. Ürünlerin farklı özellik kümelerine sahip olduğu bir katalogda document modeli uygun olabilir. Bir dizüstü bilgisayarın RAM kapasitesi bulunurken bir ayakkabının numarası ve malzemesi bulunabilir; her kategori için aynı kolonları kullanmak zorunda kalmazsınız.

Fakat esnek schema, veri modellemenin gereksiz olduğu anlamına gelmez. Document içine gömülen bilgiler birlikte okunmayı kolaylaştırabilir, ancak aynı bilginin birçok document içinde tekrar edilmesi güncelleme maliyetini artırabilir. Document büyüklüğü, indeksler ve transaction gereksinimleri yine tasarım kararlarını etkiler.

Key-value store farklı bir erişim yaklaşımı sunar. Veri, bir key üzerinden bulunur ve ilişkisel sorgulama yerine doğrudan erişim ön plana çıkar. Redis bu modelin en yaygın araçlarından biridir; string, hash, set ve sorted set gibi veri yapıları da sunar.

Redis'in güçlü olduğu alan, belirli bir key üzerinden hızlı erişim gerektiren işlemlerdir. Session saklama, rate limiting, geçici sayaçlar ve caching buna örnektir. Ancak Redis'i ilişkisel kayıtların yerine koymak, JOIN ve transaction gerektiren iş kurallarını uygulama katmanına taşımak anlamına gelebilir.

Elasticsearch ise farklı bir ihtiyaca cevap verir. Inverted index kullanarak metin içindeki terimlerden ilgili document kayıtlarına ulaşmayı sağlar. Full-text search, relevance scoring, autocomplete ve bazı analitik sorgular için uygundur. PostgreSQL de full-text search sunar; Elasticsearch'e geçiş, mevcut çözümün ölçülen ihtiyaçları karşılamadığı noktada değerlendirilmelidir.

Buradaki önemli ayrım şudur: SQL, NoSQL, Redis ve Elasticsearch aynı problemi çözmeye çalışan dört eşdeğer seçenek değildir. Farklı veri erişim ihtiyaçları için farklı optimizasyonlar sunarlar.

Consistency ve dağıtık sistem sınırları mimariyi değiştirir

Veritabanı kararlarında sık yapılan ikinci hata, ölçeklenebilirliği yalnızca daha fazla sunucu eklemek olarak görmektir. Dağıtık sistemlerde partitioning, replication, consistency ve availability arasında gerçek tasarım maliyetleri vardır.

Partitioning, verinin farklı parçalara ayrılarak saklanmasıdır. Bir müşteri tablosunu müşteri kimliğine göre bölmek veya zaman serisi kayıtlarını tarih aralıklarına ayırmak buna örnektir. Partitioning doğru sorgularda işlenecek veri miktarını azaltabilir, ancak partition key kötü seçilirse yük birkaç partition üzerinde toplanabilir.

Replication, verinin birden fazla kopyasının tutulmasıdır. Yüksek availability, okuma kapasitesi veya felaket kurtarma amacıyla kullanılabilir. Fakat replication otomatik olarak bütün kopyaların aynı anda aynı veriyi göstereceği anlamına gelmez.

Asynchronous replication kullanan bir sistemde primary üzerinde gerçekleşen güncelleme replica'ya gecikmeli ulaşabilir. Kullanıcı bir siparişi güncelledikten hemen sonra replica üzerinden okuma yaparsa eski durumu görebilir. Buna replication lag kaynaklı stale read denir.

Consistency, bir sistemin okuma ve yazma işlemleri arasında sunduğu görünürlük garantilerini anlatır. Strong consistency gerektiren bir akışta, tamamlanmış bir yazma işleminden sonraki okumaların belirlenen sözleşmeye uygun biçimde güncel değeri görmesi beklenir. Eventual consistency yaklaşımında ise eşzamanlı yeni güncellemeler olmadığı sürece kopyalar zamanla aynı duruma yaklaşır.

Bu kavramları ACID içindeki consistency ile karıştırmamak gerekir. ACID consistency, transaction işlemlerinin tanımlı veri bütünlüğü kurallarını korumasıyla ilgilidir. Dağıtık consistency modelleri ise özellikle farklı node'lar arasında hangi değerin ne zaman gözlemlenebileceğiyle ilgilenir.

CAP theorem de sıklıkla yanlış kullanılır. Teorem, network partition yaşandığında dağıtık bir sistemin bütün istekler için hem linearizable consistency hem de availability garantisini aynı anda sağlayamayacağını söyler. Bu, herhangi bir sistemin her koşulda üç özellikten yalnızca ikisini seçtiği anlamına gelmez.

Kurumsal bir ödeme sisteminde stale balance kabul edilemeyebilir. Buna karşılık ürün arama sonuçlarının yeni eklenen bir ürünü birkaç saniye geç göstermesi kabul edilebilir. Aynı uygulama içinde farklı consistency gereksinimleri bulunması normaldir.

Bu nedenle mimariyi tek bir consistency tercihiyle tanımlamak yerine işlem bazında karar vermek gerekir. Para hareketleri ve stok rezervasyonları için güçlü garantiler, arama indeksleri ve bazı raporlama ekranları için gecikmeli güncelleme uygun olabilir.

Sipariş sistemi üzerinden gerçek veri akışı

Bir e-ticaret sisteminin sipariş oluşturma akışını düşünelim. Backend, PostgreSQL üzerinde customers, orders, order_items, inventory ve payments tablolarını yönetiyor olsun. Aynı sistem ürün araması için Elasticsearch, cache için Redis kullanıyor olabilir.

Müşteri sipariş verdiğinde backend önce iş kurallarını doğrular. Sipariş kaydı oluşturulur, sipariş kalemleri eklenir ve stok rezervasyonu yapılır. Stok miktarının negatif olmaması gerekiyorsa bu kural yalnızca uygulamanın önce stok okuyup sonra güncellemesine bırakılmamalıdır.

Çünkü iki eşzamanlı istek aynı stok değerini okuyabilir. Örneğin stokta yalnızca 1 ürün varken iki farklı sipariş aynı anda oluşturulursa, kontrol ve güncelleme ayrı işlemler olduğunda ikisi de başarılı görünebilir. Row-level locking veya koşullu UPDATE gibi tekniklerle bu yarış durumu kontrol edilmelidir.

PostgreSQL üzerinde UPDATE inventory SET available = available - 1 WHERE product_id = 42 AND available >= 1 RETURNING available yaklaşımı, ilgili satırda yeterli stok bulunduğunda güncellemenin gerçekleşmesini sağlar. Hiç satır dönmemesi rezervasyonun başarısız olduğunu gösterir. Sipariş kaydıyla birlikte aynı transaction içinde kullanıldığında stok ve sipariş değişiklikleri birlikte commit edilebilir.

Ödeme işlemi ise farklı bir sınır oluşturur. Harici payment provider çağrısını açık bir database transaction içinde bekletmek çoğu durumda doğru değildir. Uzun transaction, lock süresini artırır ve harici servis gecikmesini veritabanına taşır.

Bunun yerine siparişin ödeme bekleyen durumu kaydedilebilir, ödeme işlemi ayrı yürütülebilir ve provider sonucuna göre durum güncellenebilir. Tekrarlanan callback veya request işlemleri için idempotency gerekir. Idempotency, aynı mantıksal işlemin tekrar çalıştırıldığında ikinci kez ödeme veya sipariş oluşturmamasını sağlayan davranıştır.

Sipariş oluşturulduktan sonra arama veya raporlama sistemlerinin bilgilendirilmesi gerekebilir. Burada transactional outbox pattern kullanılabilir. Uygulama, sipariş değişikliğiyle birlikte outbox tablosuna bir event kaydını aynı transaction içinde yazar. Ayrı bir worker bu kaydı okuyarak ilgili sistemlere iletir.

Bu yaklaşım database commit başarılı olduktan sonra event yayınlamanın unutulması riskini azaltır. Ancak otomatik olarak exactly-once delivery sağlamaz. Worker aynı event'i tekrar gönderebilir; consumer tarafında idempotent işleme veya deduplication gerekir.

Elasticsearch üzerinde ürün arama document kayıtları tutuluyorsa bu kayıtlar PostgreSQL'deki ürün verilerinden üretilebilir. Arama indeksi burada source of truth değildir. Source of truth, belirli bir bilginin yetkili ve doğru kabul edilen ana kaynağıdır.

Bir ürünün fiyatı değiştiğinde PostgreSQL güncellenir, ardından Elasticsearch indeksi yenilenir. İndeksleme gecikirse arama sonuçlarında eski fiyat görünebilir. Bu nedenle ödeme aşamasında fiyatı arama document kaydından almak yerine yetkili kaynaktan doğrulamak gerekir.

Aynı ayrım Redis için de geçerlidir. Ürün detayları Redis'te cache olarak bulunabilir, ancak sipariş tutarını kesinleştiren işlem yalnızca cache değerine güvenmemelidir. Özellikle fiyat, yetki veya stok gibi doğruluk gerektiren alanlarda cache verisinin ne kadar eski olabileceği açıkça tanımlanmalıdır.

Redis performansı artırır, veri sahipliğini devralmaz

Caching, sık kullanılan verinin daha hızlı erişilebilen bir katmanda tutulmasıdır. Redis çoğunlukla memory üzerinden çalıştığı için uygun erişim modellerinde veritabanına gitmekten daha düşük latency sağlayabilir. Ancak toplam performans kazancı cache hit ratio, network maliyeti, serialization ve verinin yeniden oluşturulma maliyetine bağlıdır.

Cache Aside, kurumsal backend sistemlerinde yaygın kullanılan bir caching pattern'idir. Uygulama önce Redis üzerinde ilgili key'i arar. Kayıt varsa cache üzerinden döner; bulunmazsa PostgreSQL'den okur, sonucu Redis'e yazar ve isteği tamamlar.

Örneğin product:42:details key'i bir ürünün detaylarını tutabilir. Redis'te kayıt yoksa backend PostgreSQL sorgusunu çalıştırır ve sonucu belirli bir TTL ile cache'e koyar. TTL, kaydın cache içinde otomatik olarak ne kadar süre geçerli kalacağını belirleyen süredir.

TTL için evrensel doğru bir sayı yoktur. Ürün açıklamaları dakikalar boyunca cache'te kalabilirken hızla değişen stok bilgisi çok daha kısa süre gerektirebilir veya hiç cache'lenmeyebilir. Belirleyici olan, uygulamanın stale data karşısındaki iş davranışıdır.

Cache invalidation burada temel problemdir. PostgreSQL'deki ürün değiştiğinde Redis'teki eski değerin ne zaman kaldırılacağı veya yenileneceği belirlenmelidir. En basit yaklaşım, başarılı database update sonrasında ilgili cache key'ini silmektir.

Fakat bu işlem bile tam garanti sağlamaz. Bir request eski değeri database'den okurken başka bir request güncelleme yapıp cache key'ini silebilir. İlk request daha sonra eski değeri yeniden cache'e yazabilir. Böylece invalidation tamamlanmış görünmesine rağmen stale data tekrar oluşabilir.

Bu yarış durumunu yönetmek için versioned cache key, event tabanlı invalidation veya kritik işlemlerde cache bypass gibi yöntemler kullanılabilir. Her çözüm maliyet getirir. Cache'in doğruluk gereksinimi yükseldikçe mimari karmaşıklığı da artar.

Cache stampede başka bir risk oluşturur. Popüler bir key aynı anda expire olduğunda çok sayıda request veritabanına yönelir. Request coalescing, lock kullanımı veya TTL değerlerine kontrollü jitter eklenmesi bu yükü azaltabilir.

Hot data, sık erişilen veya düşük latency gerektiren aktif veridir. Cold data ise seyrek erişilen, çoğunlukla geçmişe dönük veya arşiv niteliğindeki veridir. Bu ayrım yalnızca verinin yaşıyla ilgili değildir; eski bir müşteri kaydı tekrar yoğun kullanılmaya başladığında hot data haline gelebilir.

Hot data Redis veya hızlı indekslerle desteklenebilir. Cold data daha düşük maliyetli storage, partitioning veya arşivleme politikalarıyla yönetilebilir. Ancak finansal saklama yükümlülükleri, denetim gereksinimleri ve veri silme politikaları arşiv kararını etkiler.

Redis persistence seçenekleri sunsa da onu otomatik olarak primary database kabul etmek doğru değildir. RDB snapshot ve AOF gibi mekanizmaların durability davranışı yapılandırmaya bağlıdır. Replication da yanlışlıkla silinen bir key'i veya uygulama hatasını tek başına geri alamaz.

Polyglot Persistence için doğru başlangıç noktası

Polyglot Persistence, aynı sistemde farklı veri modelleri ve erişim ihtiyaçları için birden fazla persistence teknolojisinin kullanılmasıdır. PostgreSQL'in transactional kayıtları yönetmesi, Redis'in caching sağlaması ve Elasticsearch'ün arama yapması bu yaklaşımın tipik örneğidir.

Ancak Polyglot Persistence, mümkün olduğunca fazla veritabanı kullanmak anlamına gelmez. Her yeni teknoloji backup, monitoring, access control, deployment, migration ve incident response yükü getirir. Veri birden fazla sisteme kopyalandığında senkronizasyon sorumluluğu da ortaya çıkar.

Benim önerim, yeni bir kurumsal sistemde güçlü bir gerekçe yoksa PostgreSQL veya MSSQL gibi olgun bir relational database ile başlamaktır. Önce schema, transaction sınırları, constraint'ler ve indeksler doğru kurulmalıdır. Read-heavy sorgular için execution plan incelenmeli, gereksiz veri çekimi azaltılmalı ve uygun durumlarda pagination kullanılmalıdır.

Bir sorgu yavaş çalışıyorsa Redis eklemek ilk çözüm olmamalıdır. Eksik indeks, yanlış JOIN, gereksiz N+1 query veya büyük bir tablonun kontrolsüz taranması cache ile gizlenebilir; problem ortadan kalkmaz. Önce EXPLAIN ANALYZE gibi araçlarla sorgunun gerçek çalışma davranışı ölçülmelidir.

Redis, tekrar eden okumaların database üzerinde anlamlı yük oluşturduğu ve stale data politikasının tanımlanabildiği noktada eklenmelidir. Elasticsearch, full-text search gereksinimi mevcut relational search özelliklerinin sınırını aştığında değerlendirilmelidir. Document database ise verinin document sınırları doğal, sorgular document merkezli ve ilişkisel bütünlük ihtiyacı sınırlı olduğunda güçlü bir seçenek olabilir.

Bu önerinin geçerli olmadığı durumlar da vardır. Çok yüksek hacimli event ingestion, doğal document agregatları, özel zaman serisi gereksinimleri veya farklı coğrafyalarda belirli availability hedefleri bulunan sistemler baştan başka bir primary storage modeline ihtiyaç duyabilir. Böyle durumlarda relational database varsayılanı savunulacak bir ilke değil, test edilmesi gereken bir başlangıç hipotezidir.

Karar verilmeden önce her veri kümesi için dört şey yazılı hale getirilmelidir: Yetkili veri kaynağı, temel access pattern, kabul edilen stale data süresi ve hata durumunda beklenen davranış. Ardından gerçekçi veri hacmi ve eşzamanlılık altında ölçüm yapılmalıdır. Mimari, bu sözleşmeleri sağlayan en az sayıda bileşenden oluşmalıdır.

Kurumsal sistemlerde iyi veri mimarisi, en hızlı teknolojiyi seçmek değil, hangi verinin nerede doğru kabul edildiğini ve hangi işlemin hangi garantilerle tamamlandığını kesinleştirmektir. SQL, NoSQL ve Redis ancak bu kararların ardından yerlerine oturur.

yorumlar

0

Henüz yorum yok. İlk notu sen bırak.

Yorum yazmak için giriş yap.

Gmail ile saniyeler içinde, ya da e-posta ile kaydol.

bağlı 26109:33:00