MongoDB Sharding: Büyük Ölçekli Veri Setleri İçin Yatay Ölçekleme Stratejileri
Modern uygulama mimarilerinde veri hacmi ve işlem yükü, tek bir sunucunun veya replika setinin kapasitesini aşabilir. MongoDB bu tür senaryolar için yatay ölçekleme çözümü olarak Sharding mimarisini sunar. Bu strateji, veri kümelerini birden çok sunucuya (shard) dağıtarak hem depolama kapasitesini hem de okuma/yazma performansını artırır.
MongoDB Sharding Nedir?
Sharding, büyük bir veri kümesini daha küçük, yönetilebilir parçalara bölme ve bu parçaları farklı makinelere dağıtma işlemidir. MongoDB'de bir sharded cluster üç ana bileşenden oluşur:
- Shards: Veri parçalarını depolayan ve işleyen bağımsız
mongodörnekleri veya replika setleridir. Her shard, veri kümesinin bir alt kümesini barındırır. - Config Servers: Küme meta verilerini (hangi verinin hangi shard'da olduğu gibi eşleme bilgileri) depolayan özel
mongodörnekleridir. Bu sunucular kritik öneme sahiptir ve genellikle bir replika seti olarak yapılandırılır. - Query Routers (mongos): Uygulama ile etkileşim kuran arayüzdür.
mongos, istemci sorgularını doğru shard'a yönlendirir, birden fazla shard'dan gelen sonuçları toplar ve istemciye döndürür.
Shard Key Seçiminin Kritik Önemi
Sharding mimarisinin başarısı doğrudan shard key seçimine bağlıdır. Shard key, MongoDB'nin veriyi shards arasında nasıl dağıtacağını belirleyen bir veya daha fazla alanın birleşimidir. Yanlış seçilmiş bir shard key, dengesiz veri dağıtımına (hotspot), performansı düşüren "jumbo chunk"lara veya verimsiz sorgulara yol açabilir.
İdeal Shard Key Özellikleri:
- Kardinalite (Cardinality): Yüksek kardinaliteye sahip olmalı. Çok sayıda benzersiz değere sahip bir alan, verinin shards arasında daha eşit dağıtılmasını sağlar. Örneğin,
_idalanı genellikle iyi bir kardinaliteye sahiptir. - Düşük Frekans (Low Frequency): Belirli bir anahtar değerine çok sık erişilmemeli veya bu değere çok fazla veri eklenmemeli. Yüksek frekans, tek bir shard üzerinde aşırı yük (hotspot) yaratabilir.
- Değişmezlik (Immutability): Shard key değeri, belge bir kez eklendikten sonra değiştirilmemelidir. Değişiklikler, belgenin taşınmasına ve performans düşüşlerine neden olabilir.
- Sorgu Yalıtımı (Query Isolation): Sık yapılan sorguların belirli bir shard veya az sayıda shard'ı hedeflemesini sağlamalı. Bu,
mongos'un tüm shard'ları sorgulamasını (scatter-gather) engeller ve performansı artırır.
Shard Key Türleri:
- Range-Based Sharding (Aralık Tabanlı): Belirli bir aralıktaki değerlere sahip belgeleri aynı shard'da tutar. Sıralı erişim gerektiren sorgular için etkilidir, ancak yazma işlemleri belirli aralıklarda yoğunlaşırsa hotspot'lara neden olabilir. Örneğin, zaman damgasına göre sharding.
- Hashed Sharding (Hash Tabanlı): Shard key'in hash değerini kullanarak veriyi shards arasında rastgele dağıtır. Bu, yazma işlemlerinin shards arasında eşit dağılmasını sağlar, ancak aralık sorguları için tüm shard'ların taranması gerekebilir.
- Compound Sharding (Bileşik Anahtar): Birden fazla alanı birleştirerek bir shard key oluşturur. Örneğin,
{ "kullaniciId": 1, "tarih": 1 }. Bu, hem belirli kullanıcıların verilerini bir arada tutarken hem de zaman bazlı sorgulara olanak tanır.
Gerçek Dünya Senaryosu: E-ticaret Platformu Ürün Kataloğu
Büyük bir e-ticaret platformunun ürün kataloğunu düşünelim. Milyonlarca ürün ve her ürün için yüzlerce farklı özellik (renk, beden, marka, kategori vb.) mevcut. Geleneksel bir replika seti, veri boyutunu ve sorgu yükünü kaldıramaz hale gelebilir.
Bu senaryoda, ürün verilerini productId veya kategoriId üzerinden sharding yapmak düşünülebilir. Eğer çoğu sorgu belirli bir kategori içindeki ürünleri arıyorsa, kategoriId iyi bir range-based shard key olabilir. Ancak bu durumda, büyük kategoriler "hotspot" oluşturma riski taşır. Daha iyi bir yaklaşım, { "kategoriId": 1, "_id": "hashed" } gibi bir bileşik anahtar kullanmak olabilir. Bu, kategori bazlı sorgular için belirli bir shard kümesini hedeflemeyi sağlarken, aynı kategori içindeki ürünlerin _id hash'i sayesinde daha eşit dağılmasını sağlar.
// Örnek bir sharding komutu
sh.shardCollection("ecommerce.products", { "kategoriId": 1, "_id": "hashed" })
Bu komut, ecommerce veritabanındaki products koleksiyonunu, kategoriId ve _id alanlarını kullanarak shard eder. kategoriId için range-based, _id için ise hashed sharding uygulanır.
Sharded Cluster Kurulumu ve Yönetimi
Bir MongoDB sharded cluster kurmak, dikkatli planlama ve adımları gerektirir:
- Config Server Replika Seti Kurulumu: İlk olarak, küme meta verilerini barındıracak üç adet
mongodörneğinden oluşan bir replika seti oluşturulur. - Shard Replika Setleri Kurulumu: Veri parçalarını barındıracak her bir shard için bağımsız
mongodreplika setleri kurulur. Her shard genellikle en az üç düğümden oluşur. - Mongos Yönlendiricileri Kurulumu: Uygulama bağlantılarını yönetecek
mongosörnekleri başlatılır. Bu örnekler, config sunucularına bağlanarak küme meta verilerine erişir. - Sharding'i Etkinleştirme:
mongosüzerindensh.enableSharding("veritabaniAdi")vesh.shardCollection("veritabaniAdi.koleksiyonAdi", { shardKeyAlanlari })komutları ile belirli veritabanları ve koleksiyonlar için sharding etkinleştirilir.
// 1. Config Sunucusu Replika Setini Başlatma (örnek)
// mongod --configsvr --replSet rs_config --dbpath /data/configdb --port 27019 --bind_ip 0.0.0.0
// 2. Replika setini başlat (ilk düğümde)
// rs.initiate({ _id: "rs_config", members: [{ _id: 0, host: "config01:27019" }, { _id: 1, host: "config02:27019" }, { _id: 2, host: "config03:27019" }] })
// 3. Shard Replika Setini Başlatma (örnek - her shard için ayrı)
// mongod --shardsvr --replSet rs_shard01 --dbpath /data/shard01db --port 27018 --bind_ip 0.0.0.0
// 4. Mongos Yönlendiricisini Başlatma
// mongos --configdb rs_config/config01:27019,config02:27019,config03:27019 --port 27017 --bind_ip 0.0.0.0
// 5. Shard'ları kümeye ekleme (mongos üzerinden)
// sh.addShard("rs_shard01/shard01a:27018,shard01b:27018,shard01c:27018")
// sh.addShard("rs_shard02/shard02a:27018,shard02b:27018,shard02c:27018")
// 6. Veritabanı ve Koleksiyon için Sharding'i Etkinleştirme
// sh.enableSharding("mydatabase")
// sh.shardCollection("mydatabase.mycollection", { "myShardKeyField": 1 })
Bu örnekler, kurulum adımlarının temel bir özetidir ve üretim ortamları için daha detaylı güvenlik, ağ yapılandırması ve izleme gerektirir.
Üretim Ortamında Sharding Optimizasyonu ve Bakımı
Sharded bir kümenin kurulması sadece başlangıçtır. Optimum performans ve istikrar için sürekli optimizasyon ve bakım şarttır.
- Balanslama (Balancing): MongoDB, veriyi shards arasında otomatik olarak dengelemek için bir balancer süreci kullanır. Balancer, chunk'ları (veri blokları) daha az yüklü shard'lara taşır. Ağır iş yükleri altında, balancer'ın çalışma saatlerini ayarlamak veya belirli zamanlarda geçici olarak durdurmak gerekebilir.
- Chunk Boyutu: Varsayılan chunk boyutu 64MB'dir. Çok küçük chunk'lar meta veri yükünü artırırken, çok büyük chunk'lar dengesiz dağıtıma (jumbo chunk) yol açabilir. İş yüküne göre bu boyutu ayarlamak önemlidir.
- Sorgu Performansı: Sharded bir ortamda sorgu performansını izlemek kritik öneme sahiptir.
explain()fonksiyonu, sorguların hangi shard'lara gittiğini ve nasıl yürütüldüğünü anlamak için kullanılır. Shard key'i içermeyen sorgular genellikle "scatter-gather" tipinde olur ve tüm shard'ları tarayarak performansı düşürebilir. - Donanım Seçimi: Shard'lar için aynı veya benzer donanım özelliklerine sahip sunucular kullanmak, performans tutarlılığı açısından önemlidir. Config sunucularının ise düşük gecikmeli, yüksek I/O kapasiteli disklere sahip olması önerilir.
Gerçek Dünya Senaryosu: Log Toplama Sistemi
Büyük ölçekli bir mikroservis mimarisinde, saniyede yüzbinlerce log kaydı üreten bir log toplama sistemi düşünün. Bu loglar genellikle zaman damgasıyla etiketlenir ve belirli bir süre sonra silinir veya arşivlenir (TTL indeksleri). Bu senaryoda:
- Log verilerini
timestampalanı üzerinden sharding yapmak mantıklı görünebilir. Ancak bu, tüm yeni yazma işlemlerinin en son zaman damgasına sahip shard'a yönelmesine ve o shard'ın aşırı yüklenmesine neden olur (hotspot). - Bu durumun önüne geçmek için
{ "timestamp": 1, "serviceId": "hashed" }veya daha iyisi{ "timestamp": "hashed", "serviceId": 1 }gibi bileşik bir anahtar kullanılabilir.timestamp'i hashed yapmak, yazma işlemlerini daha eşit dağıtırken,serviceIdile belirli bir servisin loglarını bir arada tutmaya yardımcı olabilir (ancak bu durumdaserviceId'nin kardinalitesine ve sorgu paternlerine dikkat etmek gerekir). - Eğer ana sorgu paternleri belirli bir zaman aralığındaki logları getiriyorsa,
timestamp'in range-based olması daha iyi olabilir. Hotspot riskini azaltmak için,timestamp'i bir günlük veya saatlik dilime indirgeyen bir değerle (örneğin,{ "dayOfYear": 1, "timestamp": "hashed" }) sharding yapılabilir. Bu, belirli bir günün verilerini belirli bir shard grubuna yönlendirirken, o gün içindeki yazmaları hashleyerek dağıtır.
Sonuç
MongoDB sharding, veri büyüdükçe performans gereksinimlerini karşılamak için güçlü bir yatay ölçekleme çözümüdür. Doğru shard key seçimi, küme mimarisinin anlaşılması ve sürekli izleme/optimizasyon, bu kompleks yapının üretim ortamlarında başarılı bir şekilde çalışmasını sağlar. Her ne kadar başlangıçta kurulum ve yönetim maliyetleri olsa da, büyük veri setleri ve yüksek trafikli uygulamalar için sunduğu ölçeklenebilirlik, bu yatırımı fazlasıyla haklı çıkarır.