Büyük ölçekli uygulamalar geliştirirken bir noktada tek bir MongoDB sunucusunun yetmediğini fark edersiniz. Veri büyüdükçe sorgular yavaşlar, yazma işlemleri darboğaz oluşturur ve disk kapasitesi kritik seviyelere ulaşır. İşte bu noktada MongoDB’nin en güçlü silahı devreye girer: Sharding. Bu yazıda shard cluster mimarisini en ince ayrıntısına kadar ele alacak, gerçek dünya senaryolarıyla birlikte nasıl kurulacağını anlatacağım.
MongoDB Sharding Nedir ve Neden Gerekli?
Sharding, verileri birden fazla sunucuya yatay olarak dağıtma işlemidir. Dikey ölçekleme (daha güçlü donanım) bir noktaya kadar çalışır ama hem pahalıdır hem de sınırı vardır. Yatay ölçekleme ise teorik olarak sonsuz kapasiteye ulaşmanızı sağlar.
Gerçek dünya örneği vermek gerekirse: E-ticaret platformunuzda günlük milyonlarca sipariş, ürün görüntüleme ve kullanıcı davranışı verisi birikiyor. Tek sunucuda bu veri 10 TB’ı geçtiğinde sorgular dakikalarca sürebilir. Sharding ile bu yükü 5, 10 veya 20 sunucuya dağıtabilirsiniz.
Shard Cluster Bileşenleri
Bir MongoDB shard cluster üç temel bileşenden oluşur:
Shardlar (Veri Düğümleri)
Her shard, gerçek verilerin saklandığı bileşendir. Üretim ortamlarında her shard bir replica set olarak yapılandırılır. Tek node shard asla kullanmayın, çünkü bu hem veri güvenliği hem de yüksek erişilebilirlik açısından kritik bir risk oluşturur.
- Primary shard: Yazma işlemlerini alan ana düğüm
- Secondary shard: Replikasyon ile primary’dan veri alan düğümler
- Arbiter: Oy hakkı olan ama veri saklamayan düğüm (küçük ortamlar için)
Config Sunucuları
Config sunucuları, cluster’ın meta verilerini saklar. Hangi chunk’ın hangi shard’da olduğunu, shard key aralıklarını ve cluster yapılandırmasını burada bulursunuz. Üretimde mutlaka 3 node’lu bir replica set olarak kurulmalıdır. Config sunucuları çökerse cluster erişilemez hale gelir, bu yüzden bu bileşene özel önem gösterin.
mongos (Query Router)
mongos, uygulamalar ile shard cluster arasında köprü görevi görür. Uygulama direkt shardlara bağlanmaz, mongos’a bağlanır. mongos, hangi sorgunun hangi shard’a gideceğini belirler ve sonuçları birleştirerek uygulamaya döndürür. Yük dengelemesi için birden fazla mongos instance çalıştırmak iyi bir pratiktir.
Ortam Hazırlığı
Bu yazıda 7 sunuculu bir örnek ortam kuracağız. Küçük bir üretim senaryosu olarak düşünebilirsiniz:
- 3 Config Server: config1, config2, config3 (10.0.1.10-12)
- 2 Shard (her biri 2 node replica set): shard1-primary, shard1-secondary, shard2-primary, shard2-secondary (10.0.2.10-13)
- 1 mongos: mongos1 (10.0.1.20)
Tüm sunuculara MongoDB kurulumu yapıyoruz:
# Ubuntu 22.04 için MongoDB 7.0 kurulumu
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc |
sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ]
https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" |
sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org
# Servisi başlat ve enable et
sudo systemctl enable mongod
sudo systemctl start mongod
Config Sunucularını Yapılandırma
Config sunucuları için özel bir replica set kuruyoruz. Bu replica set’in adı genellikle configReplSet olur.
# /etc/mongod.conf - Config sunucularında
storage:
dbPath: /var/lib/mongodb
wiredTiger:
engineConfig:
cacheSizeGB: 2
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
net:
port: 27019
bindIp: 0.0.0.0
replication:
replSetName: "configReplSet"
sharding:
clusterRole: configsvr
Config sunucularında servis başlatıldıktan sonra replica set’i başlatıyoruz:
# config1 sunucusuna bağlan
mongosh --host 10.0.1.10 --port 27019
# Replica set'i başlat
rs.initiate({
_id: "configReplSet",
configsvr: true,
members: [
{ _id: 0, host: "10.0.1.10:27019" },
{ _id: 1, host: "10.0.1.11:27019" },
{ _id: 2, host: "10.0.1.12:27019" }
]
})
# Durumu kontrol et
rs.status()
Shardları Yapılandırma
Her shard’ı ayrı bir replica set olarak kuruyoruz. İlk shard için:
# /etc/mongod.conf - Shard1 sunucularında
storage:
dbPath: /var/lib/mongodb
wiredTiger:
engineConfig:
cacheSizeGB: 8
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
net:
port: 27018
bindIp: 0.0.0.0
replication:
replSetName: "shard1ReplSet"
sharding:
clusterRole: shardsvr
# shard1-primary'a bağlan
mongosh --host 10.0.2.10 --port 27018
# Shard1 replica set'ini başlat
rs.initiate({
_id: "shard1ReplSet",
members: [
{ _id: 0, host: "10.0.2.10:27018", priority: 2 },
{ _id: 1, host: "10.0.2.11:27018", priority: 1 }
]
})
Shard2 için aynı işlemi shard2ReplSet adıyla ve 10.0.2.12-13 IP’leriyle tekrarlayın.
mongos Yapılandırması ve Cluster Birleştirme
mongos, mongod.conf değil mongos.conf ile yapılandırılır ve clusterRole içermez:
# /etc/mongos.conf
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongos.log
net:
port: 27017
bindIp: 0.0.0.0
sharding:
configDB: configReplSet/10.0.1.10:27019,10.0.1.11:27019,10.0.1.12:27019
mongos’u systemd servisi olarak başlatmak için:
# /etc/systemd/system/mongos.service
[Unit]
Description=MongoDB Shard Router
After=network.target
[Service]
User=mongodb
Group=mongodb
ExecStart=/usr/bin/mongos --config /etc/mongos.conf
PIDFile=/var/run/mongodb/mongos.pid
LimitFNOFILE=64000
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable mongos
sudo systemctl start mongos
Artık mongos üzerinden cluster’a bağlanıp shardları ekleyebiliriz:
# mongos'a bağlan
mongosh --host 10.0.1.20 --port 27017
# Shardları cluster'a ekle
sh.addShard("shard1ReplSet/10.0.2.10:27018,10.0.2.11:27018")
sh.addShard("shard2ReplSet/10.0.2.12:27018,10.0.2.13:27018")
# Cluster durumunu kontrol et
sh.status()
Sharding Stratejileri: Doğru Shard Key Seçimi
Bu kısım kurulumdan daha önemlidir. Yanlış shard key seçimi tüm cluster’ınızı mahvedebilir.
Hashed Sharding
Shard key değerinin hash’i üzerinden dağıtım yapar. Veriyi eşit dağıtır ama range query performansı düşer.
# Veritabanında sharding'i etkinleştir
sh.enableSharding("ecommerce")
# Hashed shard key ile collection'ı shard et
sh.shardCollection(
"ecommerce.orders",
{ "userId": "hashed" }
)
Range Sharding
Belirli değer aralıklarını belirli shard’lara yönlendirir. Zaman serisi verileri için ideal ama hotspot riski var.
# Range tabanlı sharding
sh.shardCollection(
"ecommerce.events",
{ "createdAt": 1, "userId": 1 }
)
Zone Sharding (Bölgesel Veri Yönetimi)
GDPR gibi veri yerleşim zorunlulukları için kullanışlıdır. Örneğin Avrupa kullanıcı verilerini sadece Avrupa’daki shard’larda tutabilirsiniz:
# Zone tanımla
sh.addShardToZone("shard1ReplSet", "EU")
sh.addShardToZone("shard2ReplSet", "TR")
# Zone range'i belirle
sh.updateZoneKeyRange(
"ecommerce.users",
{ "country": "DE" },
{ "country": "DEuffff" },
"EU"
)
sh.updateZoneKeyRange(
"ecommerce.users",
{ "country": "TR" },
{ "country": "TRuffff" },
"TR"
)
Chunk Yönetimi ve Balancer
MongoDB, verileri chunk adı verilen 128 MB’lık bloklara böler. Balancer servisi bu chunk’ları shard’lar arasında dengeli dağıtır.
Balancer’ı mesai saatlerinde devre dışı bırakmak için:
# mongos üzerinden
use config
db.settings.updateOne(
{ _id: "balancer" },
{
$set: {
activeWindow: {
start: "02:00",
stop: "06:00"
}
}
},
{ upsert: true }
)
# Balancer durumunu kontrol et
sh.getBalancerState()
sh.isBalancerRunning()
Bazen chunk’ların manuel bölünmesi gerekebilir, özellikle büyük bir koleksiyonu ilk kez shard’ladığınızda:
# Büyük bir chunk'ı manuel böl
sh.splitAt(
"ecommerce.orders",
{ "userId": NumberLong("500000") }
)
Güvenlik Yapılandırması
Keyfile authentication olmadan bir üretim cluster’ı düşünülemez. Tüm bileşenler aynı keyfile’ı kullanır:
# Keyfile oluştur
openssl rand -base64 756 > /etc/mongodb/keyfile
chmod 400 /etc/mongodb/keyfile
chown mongodb:mongodb /etc/mongodb/keyfile
# mongod.conf'a ekle (tüm node'larda)
security:
keyFile: /etc/mongodb/keyfile
authorization: enabled
Admin kullanıcısı oluşturma:
# Önce auth olmadan bağlan ve admin kullanıcısı oluştur
mongosh --host 10.0.1.20
use admin
db.createUser({
user: "clusterAdmin",
pwd: "guclu_sifre_buraya",
roles: [
{ role: "clusterAdmin", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" }
]
})
İzleme ve Performans Takibi
Cluster sağlığını izlemek için birkaç kritik komut:
# Genel cluster durumu
mongosh --host 10.0.1.20 -u clusterAdmin -p --authenticationDatabase admin
# Shard dağılımını gör
db.adminCommand({ listShards: 1 })
# Koleksiyon istatistiklerini kontrol et
db.orders.getShardDistribution()
# Uzun süren sorguları bul
db.adminCommand({
currentOp: true,
active: true,
secs_running: { $gt: 5 }
})
# Her shard'ın chunk sayısını gör
use config
db.chunks.aggregate([
{ $group: { _id: "$shard", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
])
Gerçek Dünya Sorunları ve Çözümleri
Hotspot Problemi
Zamansal shard key kullandığınızda (örneğin createdAt) tüm yazma işlemleri son shard’a yığılır. Bunu önlemek için compound shard key kullanın:
# Kötü: sadece zaman bazlı
sh.shardCollection("logs.access", { "timestamp": 1 })
# İyi: hash + zaman bileşimi
sh.shardCollection("logs.access", { "appId": "hashed", "timestamp": 1 })
Jumbo Chunk Problemi
Chunk’lar çok büyük olup bölünemez hale geldiğinde balancer çalışmaz. Çözüm:
# Jumbo chunk'ları bul
use config
db.chunks.find({ jumbo: true })
# mongos üzerinden jumbo flag'i temizle (dikkatli ol!)
db.adminCommand({
clearJumboFlag: "ecommerce.orders",
find: { "userId": 12345 }
})
Shard Ekleme
Kapasiteyi artırmak için yeni shard ekleme işlemi online olarak yapılabilir:
# Yeni replica set'i önceden kur, sonra cluster'a ekle
sh.addShard("shard3ReplSet/10.0.2.20:27018,10.0.2.21:27018")
# Balancer otomatik olarak chunk'ları yeni shard'a taşır
# İlerlemeyi izle
sh.status()
Yedekleme Stratejisi
Sharded cluster’da yedekleme dikkat gerektiren bir konudur. mongodump ile tüm cluster’ı yedeklemek için:
# Balancer'ı durdur (yedekleme sırasında chunk hareketi istemiyoruz)
sh.stopBalancer()
sh.isBalancerRunning() # false döndürmeli
# mongos üzerinden yedek al
mongodump
--host 10.0.1.20
--port 27017
--username clusterAdmin
--password guclu_sifre
--authenticationDatabase admin
--out /backup/mongodb/$(date +%Y%m%d)
--oplog
# Yedek sonrası balancer'ı tekrar başlat
sh.startBalancer()
Üretim ortamlarında ise her shard’ın bir secondary node’undan ayrı ayrı yedek almak hem daha hızlı hem de primary’a yük bindirmez.
Performans İpuçları
- Read preference: Secondary’lardan okuma yaparak primary’ı yazma işlemleri için boşaltın. Uygulama connection string’inize
readPreference=secondaryPreferredekleyin. - Index stratejisi: Shard key her zaman index’in başında olmalıdır. Aksi halde tüm shard’lara scatter-gather sorgu gider.
- WiredTiger cache: Her sunucuda toplam RAM’in %50-60’ını WiredTiger cache’e ayırın.
- Chunk size: Varsayılan 128 MB çoğu durum için uygundur. Çok küçük yaparsanız chunk sayısı patlar, çok büyük yaparsanız balancing yavaşlar.
- mongos sayısı: Yüksek trafikli uygulamalarda uygulama sunucusu başına bir mongos çalıştırmak en iyi pratiktir.
Sonuç
MongoDB shard cluster kurulumu ilk bakışta göz korkutucu görünebilir, ancak bileşenleri tek tek anladığınızda mantıklı ve güçlü bir mimari ortaya çıkıyor. En kritik noktaları özetlemek gerekirse:
Config sunucularını asla single node bırakmayın ve her shard’ı replica set olarak kurun. Shard key seçimi en önemli kararınızdır, sonradan değiştirmek çok zahmetlidir. Balancer’ı iş saatleri dışında çalışacak şekilde planlayın. Güvenlik için keyfile ve authentication’ı baştan kurun, sonradan eklemek daha meşakkatlidir.
Bu mimariyle günde milyarlarca dokümana yazma ve okuma yapan sistemler rahatlıkla çalışıyor. Doğru yapılandırılmış bir shard cluster, veri büyümesinin önünüzde engel değil, sadece yönetilen bir parametre haline gelmesini sağlar. Sorularınız olursa yorum bölümünde bulabilirsiniz.