Veritabanı Sharding: Ne Zaman ve Nasıl Kullanılır?

## Sharding'e Ne Zaman İhtiyaç Duyarsınız? Sharding (bölümleme), tek bir veritabanı örneğinin kapasitesini aşan veri hacmi veya yazma yükünü birden f...

Veritabanı Sharding: Ne Zaman ve Nasıl Kullanılır?

Sharding'e Ne Zaman İhtiyaç Duyarsınız?

Sharding (bölümleme), tek bir veritabanı örneğinin kapasitesini aşan veri hacmi veya yazma yükünü birden fazla örneğe dağıtma yöntemidir. Ancak sharding, ilk başvurulacak çözüm değildir. Önce şu sırayı deneyin:

  1. Dikey ölçekleme: Daha güçlü CPU, RAM, daha hızlı disk.
  2. Okuma replikaları: Okuma yükünü dağıtır, yazma yükünü dağıtmaz.
  3. Önbellekleme: Sıcak veriyi uygulama katmanında veya Redis gibi bir katmanda tutma.
  4. Tabloyu bölümleme (partitioning): Tek örnek içinde tabloyu mantıksal parçalara ayırma.
  5. Sharding: Veriyi birden fazla bağımsız örneğe dağıtma.

Sharding, uygulama karmaşıklığını kalıcı olarak artırır: dağıtık sorgular, dağıtık işlemler, yeniden dengeleme ve şema değişiklikleri zorlaşır. Bu maliyeti ancak gerçekten gerektiğinde üstlenin.

Temel Kavramlar

  • Shard key (bölüm anahtarı): Bir satırın hangi shard'a gideceğini belirleyen alan. Örneğin user_id.
  • Routing: Bir sorgunun hangi shard'a gitmesi gerektiğini belirleme.
  • Rehber tablo (lookup table): Hangi anahtarın hangi shard'da olduğunu tutan yardımcı yapı.
  • Yeniden dengeleme (rebalancing): Shard'lar arasında veri taşıma.
  • Çapraz shard sorgu: Tek bir shard'a yönlendirilemeyen, birden fazlasına dokunan sorgu. Mümkün olduğunca kaçınılması gereken sorgu tipidir.

Strateji 1: Aralık Tabanlı (Range) Bölümleme

Shard key değerleri kesintisiz aralıklara bölünür.

Shard A: user_id 1 – 1.000.000
Shard B: user_id 1.000.001 – 2.000.000
Shard C: user_id 2.000.001 – 3.000.000

Avantaj: Aralık sorguları (WHERE user_id BETWEEN ...) tek shard'a yönlenir; aralık taraması verimlidir.

Dezavantaj: Yeni kayıtlar hep en büyük aralığa düştüğü için son shard "sıcak" hale gelir (hotspot). Otomatik artan ID'lerde bu sorun belirgindir.

Ne zaman: Zaman serisi veriler veya doğal sıralı anahtarlar için uygundur; ancak yazma yükü artan anahtarlarda dağılmıyorsa dikkatli olun.

Strateji 2: Hash Tabanlı Bölümleme

Shard seçimi, anahtarın hash'ine göre yapılır:

shard_index = hash(user_id) % shard_count

Avantaj: Veri ve yazma yükü shard'lar arasında dengeli dağılır.

Dezavantaj: Aralık sorguları tüm shard'lara yayılır (scatter-gather). Shard sayısı değiştiğinde neredeyse tüm anahtarların yeri değişir; bu yüzden sabit % yerine tutarlı hash (consistent hashing) veya sabit sayıda sanal shard kullanmak yaygındır.

Strateji 3: Dizin (Directory) Tabanlı Bölümleme

Hangi anahtarın hangi shard'da olduğu ayrı bir rehber servisinde tutulur.

Avantaj: Esnektir; shard'ları taşımak, belirli kiracıları ayrı shard'a almak mümkündür.

Dezavantaj: Rehber servisi tek hata noktası ve gecikme kaynağı olur. Yüksek erişilebilirlik ve önbellekleme gerektirir.

Strateji 4: Coğrafi / Kiracı Tabanlı Bölümleme

Veri, kullanıcının bölgesine veya kiracıya göre ayrılır. Veri yerleşimi ve uyumluluk (veri ikametgahı) gereksinimleri için kullanışlıdır. Dezavantajı, kiracılar arasında büyüklük farkı olduğunda dengesizlik oluşmasıdır.

Shard Key Seçimi

Shard key seçimi, sistemin uzun vadeli davranışını belirler. Şu kriterleri gözetin:

  • Yüksek kardinalite: Az sayıda farklı değer, dengesiz dağılım demektir.
  • Sorgu desenine uygunluk: En sık kullanılan sorgular tek shard'a yönlenebilmeli.
  • Düşük çapraz shard bağımlılığı: İlişkili veriler aynı shard'da olmalı.
  • Değişmezlik: Shard key güncellenirse satır taşınması gerekir; bu yüzden mümkünse değişmeyen alan seçin.

Örneğin çok kiracılı bir uygulamada tenant_id, kullanıcı odaklı bir uygulamada user_id doğal adaylardır. created_at gibi artan bir alan tek başına shard key olarak kullanılırsa hotspot oluşur.

Uygulama Katmanında Yönlendirme

Basit bir yönlendirme mantığı şu şekilde olabilir:

function getShard(userId):
    index = hash(userId) % SHARD_COUNT
    return connections[index]

function getUser(userId):
    shard = getShard(userId)
    return shard.query("SELECT * FROM users WHERE id = ?", userId)

Bu örnekte hash deterministik olmalıdır; aynı userId her zaman aynı shard'a gitmelidir. Uygulama katmanında yönlendirme yapıyorsanız shard listesini ve bağlantı havuzlarını merkezi bir yerden yönetin; her servisin kendi kopyasını tutması tutarsızlık üretir.

Çapraz Shard Sorgular ve Toplama

WHERE user_id = ? gibi shard key içeren sorgular tek shard'a gider. Ancak WHERE email = ? gibi shard key içermeyen sorgular tüm shard'lara dağılır. Bunu yönetmek için:

  • İkincil dizin tablosu: email -> user_id eşlemesini tutan bir tablo; önce buradan user_id bulunur, sonra ilgili shard'a gidilir.
  • Global tablolar: Ülke listesi gibi küçük, az değişen tabloları her shard'da kopyalayın.
  • Uygulama tarafında birleştirme: Sonuçları uygulama katmanında toplayın. Sıralama ve sayfalama maliyetli olur; dikkatli tasarlanmalıdır.

Yeniden Dengeleme

Shard'lar dengesizleştiğinde veya shard sayısı değiştiğinde veri taşınır. İlkeler:

  • Taşımayı canlı sistemde yapıyorsanız çift yazma (dual-write) veya mantıksal replikasyon kullanın.
  • Taşıma sırasında okuma, eski ve yeni konumu kontrol etmelidir.
  • Taşıma sonrası doğrulama yapın; ardından eski kopyayı kaldırın.
  • Hash tabanlı bölümlemede sabit sayıda sanal shard kullanmak, taşımayı sınırlı sayıda sanal shard'ı taşımaya indirger.

Yaygın Hatalar

  • Sharding'i erken uygulamak: Ölçekleme ve önbellekleme yeterliyken sharding'e geçmek, gereksiz karmaşıklık üretir.
  • Yanlış shard key seçmek: Artan ID veya düşük kardinaliteli alan, hotspot ve dengesizlik yaratır.
  • Çapraz shard işlemleri: Dağıtık işlemler (2PC) yavaş ve kırılgandır; tasarımı tek shard içinde tutmaya çalışın.
  • Global benzersizlik varsayımı: Otomatik artan ID'ler shard'lar arasında çakışır; UUID veya shard'a özel aralık kullanın.
  • Rehber tabloyu güncellemeyi unutmak: Taşıma sonrası eski eşleme kalırsa yanlış shard'a gidilir.
  • Şema değişikliklerini tek seferde uygulamak: Tüm shard'larda eşzamanlı migration, kilitlenme ve kesinti riskini artırır; aşamalı uygulayın.

Güvenlik Etkileri

  • Erişim kontrolü shard bazında tutarlı olmalı: Bir shard'a erişim kısıtlı, diğerinde açık bırakılırsa yetki yükseltme riski doğar.
  • Rehber servisi hassas hedef: Hangi verinin nerede olduğunu tutan servis, saldırgan için değerli bir hedeftir; kimlik doğrulama ve şifreleme uygulayın.
  • Şifreleme anahtarları: Shard'lar arasında anahtar yönetimini merkezileştirin; anahtar karmaşası veri kaybına yol açar.
  • Bağlantı bilgileri: Her shard'ın kimlik bilgileri ayrı ayrı sızabilir; sırları merkezi bir kasada tutun ve döndürün.
  • Denetim kayıtları: Çapraz shard sorgular ve taşıma işlemleri izlenmelidir; aksi halde veri sızıntısı fark edilmez.

Özet

Sharding, ölçekleme yolculuğunun son adımlarından biridir. Doğru shard key seçimi, çapraz shard sorguların sınırlanması ve yeniden dengeleme planı olmadan sharding, sorunları çözmek yerine erteler. Küçük başlayın, sorgu desenlerinizi ölçün ve sharding'i yalnızca diğer seçenekler tükendiğinde devreye alın.

İLGİLİ İÇERİKLER

Bunları da Okumak İsteyebilirsiniz