MongoDB'de sharding, bir koleksiyonun verisini birden fazla sunucuya (shard) bölerek dağıtma yöntemidir. Hangi belgenin hangi shard'a gideceğini shard key belirler: koleksiyonu sh.shardCollection("veritabani.koleksiyon", { alan: 1 }) veya { alan: "hashed" } ile shard'larsınız. İyi bir shard key yüksek kardinaliteye sahip, değerleri dengeli dağılan, sürekli artmayan ve en sık sorgularınızda yer alan bir alandır (ya da alan birleşimidir).

Bu yazı sharded kümenin bileşenlerini, ranged ve hashed sharding farkını, shard key seçerken bakılacak ölçütleri, benzersizlik kısıtlarını ve shard key'i sonradan değiştirme yollarını anlatıyor. Sharding, replica set üzerine kurulur; temel kavramlar için önce replica set kurulumu yazısını okumanızı öneririz. Serinin tamamı MongoDB öğrenme rehberinde yer alıyor.

Neden Sharding? Dikey ve Yatay Ölçekleme

Büyük veri kümeleri veya yüksek işlem hacmi tek bir sunucunun sınırlarını zorlar. Yüksek sorgu oranları işlemciyi tüketebilir; çalışma kümesi (working set) RAM'den büyük olduğunda diskler baskı altına girer. Bu büyümeye iki yolla cevap verilir. Dikey ölçekleme tek sunucuya daha güçlü işlemci, daha fazla RAM veya disk eklemektir; mevcut donanımın ve bulut sağlayıcılarının sunduğu yapılandırmalar bunun pratik bir üst sınırını çizer. Yatay ölçekleme ise veriyi ve yükü birden fazla sunucuya bölmek, gerektikçe sunucu eklemektir. Her makine işin bir bölümünü üstlenir; bedeli altyapı ve bakımdaki artan karmaşıklıktır.

Sharding'in üç somut kazancı vardır. Okuma ve yazma yükü shard'lara dağılır ve shard ekledikçe kapasite artar. Depolama kapasitesi shard sayısıyla birlikte büyür. Shard'lar ve config sunucuları replica set olarak çalıştığı için erişilebilirlik artar; bir shard tamamen erişilemez olsa bile küme diğer shard'lardaki veriler için kısmi okuma ve yazmaya devam edebilir.

Sharded Kümenin Bileşenleri

Sharded Kümenin Bileşenleri: Shard, mongos, Config sunucuları
BileşenGöreviÜretim önerisi
ShardShard edilmiş verinin bir alt kümesini tutarHer shard 3 üyeli replica set
mongosSorgu yönlendirici, uygulama ile küme arasındaki arayüzBir veya daha fazla router
Config sunucularıKümenin meta verisini ve ayarlarını tutar3 üyeli replica set (CSRS)

Her shard bir replica set olarak kurulmak zorundadır; config sunucuları da replica set olarak çalışır. Belgelere göre MongoDB 8.0'dan itibaren config sunucusunu uygulama verisi de tutan bir config shard olarak kurmak mümkündür. Sharded veriyi dağıtmak için en az iki shard gerekir; tek shard'lı bir küme yalnızca yakın gelecekte sharding planlıyorsanız anlamlıdır. Belgeler üretimde replica set üyelerinin en az üç veri merkezine dağıtılmasını da önerir.

Birden fazla mongos çalıştırmak erişilebilirliği artırır. Uygulama ile mongos'lar arasında bir proxy veya yük dengeleyici varsa, aynı istemcinin tüm bağlantılarının aynı mongos'a gitmesini sağlayan client affinity ayarı yapılmalıdır. Router sayısını artırdıkça config sunucularıyla trafik arttığı için performans düşebilir; belgeler bu durumda router sayısını azaltmayı önerir.

Chunk, Balancer ve Veri Dağılımı

MongoDB shard edilmiş veriyi chunk adı verilen parçalara böler. Her chunk, shard key değerleri üzerinde alt sınırı dahil, üst sınırı hariç bir aralığı kapsar. Arka planda çalışan balancer, shard'lar arasında dengeli bir dağılım sağlamak için aralıkları shard'lar arasında taşır. Sharding koleksiyon düzeyinde yapılır: aynı veritabanında shard edilmiş ve edilmemiş koleksiyonlar birlikte bulunabilir. Shard edilmemiş bir koleksiyon herhangi bir shard'da durabilir ama shard'lar arasında bölünmez.

Bir belgede shard key alanlarından biri eksik olabilir. Belgelere göre eksik alanlar, belgeler shard'lara dağıtılırken null değer gibi ele alınır ve bu belgeler null shard key değerleriyle aynı chunk aralığında yaşar; sorgu yönlendirmede ise böyle ele alınmaz.

Bir Koleksiyonu Shard Etmek

Koleksiyonu shard etmek için tam ad alanını ("veritabani.koleksiyon") ve shard key belgesini verirsiniz. Değer 1 ise ranged (aralık tabanlı), "hashed" ise hashed sharding uygulanır. MongoDB 6.0'dan itibaren bunun için önce sh.enableSharding() çalıştırmanız gerekmez.

javascript
// ranged sharding: musteriId ve olusturma alanlarına göre
sh.shardCollection("magaza.siparisler", { musteriId: 1, olusturma: 1 })

// hashed sharding: tek alan
sh.shardCollection("magaza.olaylar", { cihazId: "hashed" })

// bileşik hashed shard key: ön alan aralık, son alan hash
sh.shardCollection("magaza.loglar", { bolge: 1, kayitNo: "hashed" })

Shard edilen koleksiyonun shard key ile başlayan bir indeksi olmalıdır. Koleksiyon boşsa ve uygun indeks yoksa sh.shardCollection() bu indeksi kendisi oluşturur. Koleksiyon doluysa indeksi önce sizin oluşturmanız gerekir. Shard key'i destekleyen tek gizlenmemiş indeksi silemez veya gizleyemezsiniz. İndeks oluşturma ayrıntıları için MongoDB index oluşturma ve bileşik indeksler için compound index ve ESR kuralı yazılarına bakın.

javascript
// dolu bir koleksiyonda önce indeks, sonra sharding
db.siparisler.createIndex({ musteriId: 1, olusturma: 1 })
sh.shardCollection("magaza.siparisler", { musteriId: 1, olusturma: 1 })

Hashed ve Ranged Sharding Karşılaştırması

Hashed ve Ranged Sharding Karşılaştırması: Sürekli artan alan (ObjectId, zaman damgası), Shard key üzerinde aralık sorgusu, Eşitlik sorgusu, Benzersiz (unique) shard key

Ranged sharding veriyi shard key değerlerine göre aralıklara böler. Birbirine yakın değerler büyük olasılıkla aynı chunk'ta durur; bu da mongos'un aralık sorgularını yalnızca ilgili shard'lara yönlendirmesini (targeted operation) sağlar. Verimliliği tamamen seçilen shard key'e bağlıdır; kötü seçilmiş bir key dengesiz dağılım ve darboğaz üretir.

Hashed sharding shard key alanının hash değerini hesaplar ve chunk aralıklarını bu hash değerleri üzerinden belirler. Hash'i uygulamanın hesaplaması gerekmez; MongoDB sorguları çözerken bunu kendisi yapar. Yakın değerler farklı chunk'lara dağıldığı için özellikle sürekli artan alanlarda çok daha dengeli bir dağılım elde edilir. Bedeli, shard key üzerindeki aralık sorgularının artık tek bir shard'a hedeflenememesi ve kümenin tamamına yayın (broadcast) yapılmasıdır; eşitlik sorguları ise yine tek bir shard'a yönlendirilebilir.

ÖlçütRangedHashed
Sürekli artan alan (ObjectId, zaman damgası)Yeni yazmalar tek chunk'a yığılırYazmalar dengeli dağılır
Shard key üzerinde aralık sorgusuİlgili shard'lara hedeflenirÇoğunlukla tüm shard'lara yayılır
Eşitlik sorgusuHedeflenirHedeflenir
Benzersiz (unique) shard keyMümkünHashed indekste unique tanımlanamaz
Zone kullanımıDoğrudanBileşik hashed key'in hash olmayan ön alanlarıyla

Shard Key Seçimi: Dört Ölçüt

1. Kardinalite

Kardinalite, shard key'in alabileceği farklı değer sayısıdır ve balancer'ın oluşturabileceği en fazla chunk sayısını belirler. Her benzersiz shard key değeri aynı anda yalnızca tek bir chunk'ta bulunabilir. Örneğin yalnızca üç farklı değeri olan bir uyelikTipi alanına göre shard'larsanız en fazla üç chunk oluşabilir; dördüncü bir shard eklemenin hiçbir faydası olmaz. Düşük kardinaliteli bir alanı kullanmak zorundaysanız, kardinaliteyi artırmak için onu başka alanlarla bileşik bir indekste birleştirin.

2. Değer sıklığı (frequency)

Belgelerin büyük çoğunluğu olası değerlerin küçük bir alt kümesini taşıyorsa, bu değerleri tutan chunk'lar darboğaz olur. Bu chunk'lar büyüdükçe artık bölünemeyen (jumbo) chunk'lara dönüşebilir. Yüksek kardinalite tek başına dengeli dağılımı garanti etmez; değerlerin ne sıklıkta tekrarlandığı da önemlidir. Çözüm yine benzersiz veya seyrek tekrarlanan bir alanla bileşik key kullanmaktır.

3. Monoton değişim

Sürekli artan veya azalan bir değer üzerindeki shard key, eklemeleri tek bir chunk'a yönlendirme eğilimindedir. Her kümede üst sınırı MaxKey olan bir chunk vardır; değer hep artıyorsa tüm yeni eklemeler bu chunk'a, dolayısıyla tek bir shard'a gider ve o shard yazma darboğazı olur. Azalan değerlerde aynı şey alt sınırı MinKey olan chunk için geçerlidir. ObjectId değerleri ve zaman damgaları tipik monoton alanlardır; belgeler bunlar için hashed sharding önerir ve yalnızca ObjectId içeren varsayılan _id alanını hashed shard key için iyi bir örnek olarak gösterir.

4. Sorgu kalıpları

Sorgu shard key'i veya bileşik shard key'in ön ekini içeriyorsa mongos sorguyu yalnızca ilgili shard'lara gönderir. İçermiyorsa sorgu tüm shard'lara yayılır (scatter-gather); bu sorgular uzun sürebilir ve shard ekledikçe doğrusal ölçeklenmez. Büyük miktarda veri işleyen aggregation sorgularında ise tüm shard'larda paralel çalışmak avantaj olabilir. Shard key'i belirlemeden önce en sık çalışan sorgularınızı listeleyin; mevcut sorguların planlarını incelemek için explain ve sorgu planı yazısı işe yarar.

MongoDB 7.0'dan itibaren analyzeShardKey komutu (ve db.collection.analyzeShardKey() yöntemi) aday bir shard key için metrikler hesaplar. Bunun için önce configureQueryAnalyzer ile hedef koleksiyonda sorgu örneklemesini açmanız gerekir. Çıktıdaki keyCharacteristics alanı kardinalite, sıklık ve monotonluk metriklerini; readWriteDistribution alanı ise örneklenen sorguların yönlendirme kalıplarını içerir.

Örnek: Bir Sipariş Koleksiyonu için Karar

Bir e-ticaret uygulamasında siparisler koleksiyonunu düşünelim. Belgelerde _id (ObjectId), musteriId, durum ve olusturma tarihi var. En sık sorgu "bir müşterinin siparişlerini tarihe göre listele" şeklinde.

  • { durum: 1 }: Yalnızca birkaç farklı değer (beklemede, kargoda, teslim) olduğu için kardinalitesi düşük ve değerlerin dağılımı dengesizdir. Uygun değil.
  • { olusturma: 1 }: Sürekli artar; tüm yeni siparişler MaxKey chunk'ına gider. Uygun değil.
  • { _id: "hashed" }: Yazmaları dengeli dağıtır ama "bir müşterinin siparişleri" sorgusu shard key içermediği için tüm shard'lara yayılır.
  • { musteriId: 1, olusturma: 1 }: Müşteri sayısı yüksekse kardinalite yüksektir, sorgu shard key'in ön ekini içerdiği için hedeflenir ve tek bir müşterinin tarih aralığı da aynı shard'da kalır. Birkaç müşteri siparişlerin çok büyük bölümünü oluşturuyorsa sıklık sorunu doğabileceğini akılda tutun.

Bu örnekte son seçenek sorgu kalıbı ile dağılım arasında iyi bir denge kurar. Kararı vermeden önce gerçek veriniz üzerinde analyzeShardKey ile ölçüm yapmak, tahmine dayanmaktan daha güvenilirdir.

Benzersizlik ve Sharding

Sharded bir kümede benzersizlik kısıtı shard'lar arasında ancak unique indeks shard key üzerindeyse ya da shard key'i ön ek olarak içeriyorsa uygulanır. Ranged sharding kullanan bir koleksiyonda yalnızca shard key üzerindeki indeks, shard key'in ön ek olduğu bileşik indeks veya varsayılan _id indeksi unique olabilir. Hashed indekste ise unique kısıtı tanımlanamaz. sh.shardCollection() çağrısında unique: true verirseniz koleksiyonun shard key üzerinde unique bir indeksi olmalıdır; dolu bir koleksiyonda bu indeksi önceden oluşturmanız gerekir ve shard key'i destekleyen indeks unique değilse komut hata döndürür. Benzersiz indeks hataları için E11000 duplicate key ve unique, partial ve sparse index yazılarına bakın.

Shard Key'i Sonradan Değiştirmek

Shard key seçimi kalıcı değildir ama değiştirmek pahalıdır. İki yol vardır. refineCollectionShardKey komutu mevcut key'in sonuna yeni alanlar ekleyerek onu inceltir. reshardCollection komutu (sh.reshardCollection()) ise MongoDB 5.0'dan beri koleksiyonu tamamen yeni bir key ile yeniden dağıtır; MongoDB 8.0'dan itibaren forceRedistribution: true ile aynı key üzerinde yeniden dağıtım yapıp veriyi yeni shard'lara veya zone'lara yaymak da mümkündür. Bir belgenin shard key değerini de değiştirebilirsiniz, yeter ki shard key alanı değiştirilemeyen _id olmasın; sık sık başka bir shard'ın aralığına taşınan değerler ise belgeyi shard'lar arasında göç ettirdiği için performansı etkiler.

javascript
sh.reshardCollection("magaza.siparisler", { musteriId: 1, olusturma: 1 })

Yeniden sharding öncesinde belgelerdeki gereksinimleri gözden geçirin. Her alıcı shard'da, koleksiyonun depolama boyutu ile toplam indeks boyutunun iki katının shard sayısına bölümü kadar boş alan olmalıdır. Aynı anda yalnızca bir koleksiyon yeniden shard'lanabilir, devam eden bir indeks oluşturma işlemi olmamalıdır ve writeConcernMajorityJournalDefault true olmalıdır. İşlem sürerken o koleksiyonda collMod, createIndexes, drop, dropIndexes ve renameCollection desteklenmez. Yeni key'in indeksini önceden oluşturmanız gerekmez; işlem bunu kendisi yapar. İşlemden sonra uygulamanızın sorgu filtrelerini yeni shard key'i kullanacak şekilde güncelleyin; aksi halde tam shard key içermeyen bazı yazmalar iki aşamalı ve daha yavaş bir protokolle çalışır.

Zone'lar Hakkında Kısa Not

Birden fazla veri merkezine yayılan kümelerde zone'lar veri yerelliğini iyileştirir. Her zone bir veya daha fazla shard key aralığını kapsar; aralık alt sınırı dahil, üst sınırı hariçtir. Zone aralıkları shard key alanlarıyla tanımlanır, bileşik key'de aralığın key'in ön ekini içermesi gerekir. Belgeler, zone kullanmayı düşünüyorsanız bunu shard key seçerken hesaba katmanızı önerir; zone'ları ve aralıklarını boş ya da henüz var olmayan bir koleksiyonu shard'lamadan önce tanımlamak, zone tabanlı kurulumu hızlandırır.

MongoDB 9.0 Notları

MongoDB 9.0, mongosh için sh.shardDrainingStatus() ve sh.getTransitionToDedicatedConfigServerStatus() yöntemlerini ekler, checkMetadataConsistency komutuna yeni tutarsızlık türleri ve bir chunk kontrol eşiği seçeneği getirir. Sürüm notlarındaki açık bir bilinen soruna göre sharded kümedeki düğümler her config sunucusuna en az ShardingTaskExecutorPoolMinSize kadar bağlantı açar ve bu, config sunucularının bağlantılarını tüketebilir. Bu parametreyi 1'den büyük ayarladıysanız, ayrı (dedicated) config sunucusu kullanan kümelerde etkilenen bir 9.0 sürümüne geçmeden önce ShardingTaskExecutorPoolMinSizeForConfigServers değerini 1 yapmanız önerilir. Tüm değişiklikler için MongoDB 9.0 yenilikleri yazısına bakın.

Sık Yapılan Hatalar

Sık Yapılan Hatalar: Henüz ihtiyaç yokken sharding'e geçmek. Belgeler sharded kümenin altyapı..., Sürekli artan bir alanı (tarih, sayaç, ObjectId) ranged shard key olarak seçmek...
  • Henüz ihtiyaç yokken sharding'e geçmek. Belgeler sharded kümenin altyapı gereksinimlerinin ve karmaşıklığının dikkatli planlama ve bakım gerektirdiğini vurgular; önce indeksleri ve sorguları iyileştirmek çoğu zaman yeterlidir.
  • Sürekli artan bir alanı (tarih, sayaç, ObjectId) ranged shard key olarak seçmek.
  • Düşük kardinaliteli bir alanı tek başına shard key yapmak.
  • Uygulamayı mongos yerine doğrudan bir shard'a bağlamak.
  • En sık sorgularda shard key'i kullanmayıp her sorgunun tüm shard'lara yayılmasına neden olmak.
  • Hashed shard key üzerinde benzersizlik beklemek.

Sık Sorulan Sorular

Sharding için kaç sunucu gerekir?

Belgelerdeki üretim önerisi; üç üyeli bir config sunucusu replica set'i, her biri üç üyeli replica set olan en az iki shard ve bir veya daha fazla mongos'tur. Yani üretim için tek sunucuda sharding anlamlı değildir.

Shard key değerini sorgularda hash'lemem gerekir mi?

Hayır. Hashed indeks kullanan sorgularda MongoDB hash değerini kendisi hesaplar; uygulamanız normal değerle sorgu yazar.

Shard key'i yanlış seçersem ne olur?

Belgeler kötü bir shard key'in tipik belirtilerini jumbo chunk'lar, dengesiz yük dağılımı ve düşen sorgu performansı olarak sıralar. Düzeltmek için key'i inceltebilir veya koleksiyonu yeniden shard'layabilirsiniz; ikisi de planlama ve kaynak gerektirir.

Shard edilmiş bir koleksiyonun shard key'ini nasıl görürüm?

Belgelere göre db.printShardingStatus() yöntemi koleksiyonun kullandığı shard key'i gösterir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: MongoDB öğrenme rehberi · Replica set kurulumu · Write concern ve read concern · Index oluşturma · Compound index ve ESR · Production notları