MongoDB Oplog Analizi ve Replica Set Gecikme Sorunlarının Giderilmesi
Prodüksiyon ortamında MongoDB replica set çalıştırıyorsanız ve bir gün sabah 3’te “secondary geride kalıyor” alarmıyla uyandıysanız, bu yazı tam size göre. Oplog analizi, MongoDB’nin en az anlaşılan ama en kritik konularından biri. Replication lag sorunlarını çözmek için önce oplog’un nasıl çalıştığını anlamanız gerekiyor.
Oplog Nedir ve Nasıl Çalışır
Oplog (operations log), MongoDB’de primary üzerinde gerçekleşen tüm yazma işlemlerinin sıralı kaydını tutan özel bir capped collection’dır. local.oplog.rs namespace’inde saklanır ve secondary’ler bu koleksiyonu sürekli izleyerek kendilerini günceller.
Oplog’un capped collection olması, sabit bir boyuta sahip olduğu ve dolduğunda en eski kayıtların üzerine yazıldığı anlamına gelir. İşte bu nokta kritik: eğer bir secondary yeterince hızlı sync edemezse ve oplog dolup eski kayıtların üzerine yazılırsa, o secondary artık “rollback” durumuna düşer ve manuel müdahale gerektirir.
Oplog Boyutunu Kontrol Etme
İlk yapmanız gereken şey mevcut oplog durumunuzu anlamak:
# Primary'e bağlanın
mongosh --host primary-host:27017 -u admin -p yourpassword --authenticationDatabase admin
# Oplog durumunu kontrol edin
rs.printReplicationInfo()
Bu komutun çıktısı size şunu söyler:
- configured oplog size: Yapılandırılmış oplog boyutu (MB cinsinden)
- log length start to end: Oplog’un kapsadığı süre (saat/dakika)
- oplog first event time: İlk kayıt zamanı
- oplog last event time: Son kayıt zamanı
- now: Şu anki zaman
Eğer “log length” değeriniz 2-3 saatten azsa, yüksek yazma yükünde sorun yaşamanız kaçınılmaz.
Secondary Durumunu İnceleme
# Secondary lag durumunu görmek için
rs.printSecondaryReplicationInfo()
# Ya da daha detaylı bilgi için
rs.status()
rs.status() çıktısında her üye için optimeDate ve lastHeartbeat değerlerini karşılaştırın. Primary ile secondary arasındaki fark sizin replication lag değerinizdir.
Oplog Analizi: Derinlemesine Bakış
Oplog kayıtlarını incelemek, hangi operasyonların sistemi yavaşlattığını anlamanızı sağlar. Bir oplog dokümanı şu alanları içerir:
- ts: İşlemin timestamp’i (BSON Timestamp formatında)
- op: Operasyon tipi (i=insert, u=update, d=delete, c=command, n=no-op)
- ns: Namespace (veritabanı.koleksiyon)
- o: Operasyon içeriği
- o2: Update operasyonlarında hedef doküman
# Son 100 oplog kaydını inceleyin
mongosh --quiet --eval "
db.getSiblingDB('local').oplog.rs.find().sort({ts:-1}).limit(100).forEach(function(doc) {
print(JSON.stringify({
ts: doc.ts,
op: doc.op,
ns: doc.ns,
wall: doc.wall
}));
})
"
Hangi Koleksiyon En Çok Yazma Alıyor
Oplog’da hangi namespace’in en yoğun kullanıldığını bulmak için:
mongosh --eval "
var pipeline = [
{$group: {
_id: {$concat: ['$op', ' -> ', '$ns']},
count: {$sum: 1}
}},
{$sort: {count: -1}},
{$limit: 20}
];
db.getSiblingDB('local').oplog.rs.aggregate(pipeline).forEach(printjson);
"
Bu sorgu size hangi koleksiyonların en fazla oplog kaydı ürettiğini gösterir. Eğer beklenmedik bir koleksiyon listenin başındaysa, uygulama tarafında bir sorun var demektir.
Zaman Bazlı Oplog Analizi
Belirli bir zaman aralığındaki oplog trafiğini incelemek için:
mongosh --eval "
// Son 1 saatteki oplog kayıtlarını say
var oneHourAgo = new Timestamp(Math.floor(Date.now()/1000) - 3600, 0);
var count = db.getSiblingDB('local').oplog.rs.countDocuments({ts: {$gte: oneHourAgo}});
print('Son 1 saatteki oplog kayıt sayisi: ' + count);
print('Saniye basina ortalama: ' + Math.round(count/3600));
"
Replication Lag Nedenlerini Teşhis Etme
Lag sorunlarının birkaç farklı kökeni olabilir. Bunları sistematik olarak ele alalım.
Senaryo 1: Ağ Bant Genişliği Sorunu
Secondary’nin primary’den veri çekme hızı yetersiz kalabilir. Bunu test etmek için:
# Secondary sunucusunda ağ trafiğini izleyin
iftop -i eth0 -n
# Ya da daha basit olarak
nethogs eth0
# MongoDB'nin network istatistiklerini kontrol edin
mongosh --eval "db.adminCommand({serverStatus: 1}).network" | grep -E 'bytesIn|bytesOut'
Eğer ağ doygunluğu varsa, replica set üyelerini farklı network segment’lere taşımayı ya da dedicated replication network kurmayı düşünün.
Senaryo 2: Disk I/O Darboğazı
Secondary disk yazma hızı yetişemiyorsa lag kaçınılmaz olur:
# Secondary sunucusunda I/O durumunu izleyin
iostat -xz 1 10
# MongoDB'nin disk kullanımını kontrol edin
mongosh --eval "
var ss = db.adminCommand({serverStatus: 1});
printjson(ss.wiredTiger.cache);
"
WiredTiger cache’inin “pages read into cache” değeri sürekli yüksekse, working set RAM’inizi aşıyor demektir. Bu durumda ya RAM ekleyin ya da verinizi parçalayın.
Senaryo 3: Ağır Update Operasyonları
Bazı update operasyonları oplog’da çok daha fazla yer kaplar. Özellikle $push ile array güncellemeleri ve multi-document update’ler secondary’de yüksek CPU kullanımına yol açar:
# Büyük oplog kayıtlarını bulun (10KB üzeri)
mongosh --eval "
db.getSiblingDB('local').oplog.rs.find(
{$expr: {$gt: [{$bsonSize: '$$ROOT'}, 10240]}}
).sort({ts:-1}).limit(10).forEach(function(doc){
print('Size: ' + Object.bsonsize(doc) + ' bytes, ns: ' + doc.ns + ', op: ' + doc.op);
});
"
Oplog Boyutunu Artırma
Replication lag sorunlarının en yaygın çözümlerinden biri oplog boyutunu artırmaktır. Bu işlemi canlı sistemde, rolling fashion ile yapabilirsiniz.
Mevcut Oplog Boyutunu Değiştirme
MongoDB 3.6 ve üzeri için dinamik boyut değişikliği yapılabilir:
# Primary'de oplog boyutunu 50GB olarak ayarlayın
mongosh --eval "
db.adminCommand({
replSetResizeOplog: 1,
size: 51200 // MB cinsinden, 50GB
});
"
Bu değişiklik kalıcı değil, sadece çalışan instance için geçerlidir. Kalıcı yapmak için mongod.conf dosyasını güncelleyin:
# /etc/mongod.conf dosyasına ekleyin
cat >> /etc/mongod.conf << 'EOF'
replication:
oplogSizeMB: 51200
replSetName: "rs0"
EOF
Değişikliği kontrol edin:
mongosh --eval "
use local
db.oplog.rs.stats().maxSize
"
Geride Kalan Secondary’yi Kurtarma
Eğer secondary oplog’un dışına çıktıysa (RECOVERING veya ROLLBACK durumunda), birkaç seçeneğiniz var.
Yöntem 1: İlk Senkronizasyon (Initial Sync)
En temiz yöntem:
# Secondary'deki data dizinini temizleyin
# DIKKAT: Bu işlem secondary'deki tüm veriyi siler!
# Önce servisi durdurun
sudo systemctl stop mongod
# Data dizinini temizleyin
sudo rm -rf /var/lib/mongodb/*
# Servisi yeniden başlatın, otomatik initial sync başlar
sudo systemctl start mongod
# Sync durumunu izleyin
mongosh --eval "rs.status().members.forEach(m => print(m.name, m.stateStr, m.infoMessage))"
Yöntem 2: Hızlı Kopyalama ile Sync
Büyük veritabanlarında initial sync saatler sürebilir. Daha hızlı bir yöntem:
# Primary'deki veriyi rsync ile kopyalayın
# Önce primary'de fsync ve lock alın
mongosh --eval "db.adminCommand({fsync: 1, lock: true})"
# Başka terminal'de rsync yapın
rsync -avz --progress
-e "ssh -i /path/to/key"
/var/lib/mongodb/
mongodbuser@secondary-host:/var/lib/mongodb/
# Primary'deki lock'u açın
mongosh --eval "db.adminCommand({fsyncUnlock: 1})"
# Secondary'yi başlatın
ssh secondary-host "sudo systemctl start mongod"
Monitoring ve Alerting Kurulumu
Sorun çıkmadan önce haberdar olmak için izleme sistemi kurmanız şart.
Lag Monitoring Script’i
#!/bin/bash
# /usr/local/bin/check_mongo_lag.sh
THRESHOLD_SECONDS=30
MONGO_URI="mongodb://monitor:password@localhost:27017/admin"
ALERT_EMAIL="[email protected]"
LAG=$(mongosh "$MONGO_URI" --quiet --eval "
var status = rs.status();
var primary = status.members.filter(m => m.stateStr === 'PRIMARY')[0];
var maxLag = 0;
status.members.forEach(function(m) {
if (m.stateStr === 'SECONDARY') {
var lag = (primary.optimeDate - m.optimeDate) / 1000;
if (lag > maxLag) maxLag = lag;
}
});
print(maxLag);
")
if (( $(echo "$LAG > $THRESHOLD_SECONDS" | bc -l) )); then
echo "UYARI: MongoDB replication lag ${LAG} saniye" |
mail -s "MongoDB Lag Alarmi" "$ALERT_EMAIL"
echo "$(date): LAG=${LAG}s - ALARM" >> /var/log/mongo_lag.log
else
echo "$(date): LAG=${LAG}s - OK" >> /var/log/mongo_lag.log
fi
# Script'i çalıştırılabilir yapın ve cron'a ekleyin
chmod +x /usr/local/bin/check_mongo_lag.sh
# Her 5 dakikada bir çalıştır
echo "*/5 * * * * root /usr/local/bin/check_mongo_lag.sh" >> /etc/cron.d/mongo-monitor
Prometheus ile MongoDB Exporter Kurulumu
Daha profesyonel bir izleme için mongodb_exporter kullanabilirsiniz:
# MongoDB exporter'ı indirin
wget https://github.com/percona/mongodb_exporter/releases/download/v0.39.0/mongodb_exporter-0.39.0.linux-amd64.tar.gz
tar xzf mongodb_exporter-0.39.0.linux-amd64.tar.gz
sudo mv mongodb_exporter /usr/local/bin/
# Systemd service dosyası oluşturun
cat > /etc/systemd/system/mongodb_exporter.service << 'EOF'
[Unit]
Description=MongoDB Exporter for Prometheus
After=network.target
[Service]
Type=simple
User=mongodb
ExecStart=/usr/local/bin/mongodb_exporter
--mongodb.uri=mongodb://exporter:password@localhost:27017/admin
--collect-all
--web.listen-address=:9216
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now mongodb_exporter
Grafana’da izleyeceğiniz kritik metrikler:
- mongodb_mongod_replset_member_replication_lag: Saniye cinsinden lag değeri
- mongodb_mongod_replset_oplog_size_bytes: Oplog boyutu
- mongodb_mongod_replset_oplog_head_timestamp: Oplog’un başlangıç zamanı
- mongodb_mongod_op_counters_total: Operasyon sayaçları
Oplog’u Etkileyen Uygulama Davranışları
Lag sorunlarının çoğu veritabanı değil, uygulama kaynaklıdır. Bazı yaygın anti-pattern’ler:
Bulk Write Optimizasyonu
Uygulamanız tek tek insert yapıyorsa, bulk write’a geçmek hem primary yükünü hem de oplog boyutunu dramatik biçimde azaltır. Uygulama ekibine şunu gösterin:
// Kötü yöntem - her insert ayrı oplog kaydı
for (let item of items) {
db.collection.insertOne(item);
}
// İyi yöntem - tek oplog transaction
db.collection.insertMany(items, {ordered: false});
TTL Index Temizlikleri
TTL index’ler arka planda otomatik silme yapar ve yoğun saatlerde beklenmedik oplog trafiği oluşturabilir. Bunu izleyin:
mongosh --eval "
// TTL silmelerini izle
db.adminCommand({serverStatus: 1}).metrics.ttl
"
Çıktıdaki deletedDocuments değeri hızla artıyorsa, TTL işlemi oplog’u dolduruyor olabilir. Bu durumda TTL index yerine manuel cleanup job tercih edin ya da TTL’i gece saatlerine yönlendirin.
Acil Durum: Primary Seçimi Zorlamak
Lag çok yüksek olduğunda ve primary’e erişim sorunluysa, yeni bir primary seçimi gerekebilir:
# Mevcut primary'yi secondary'ye düşürün
mongosh --eval "rs.stepDown(60)" # 60 saniye boyunca primary olmayı reddeder
# Belirli bir üyeyi primary yapmak için priority ayarı
mongosh --eval "
var cfg = rs.conf();
cfg.members[0].priority = 1; // primary kalmasın
cfg.members[1].priority = 2; // bu üye tercih edilsin
rs.reconfig(cfg);
"
Sonuç
MongoDB oplog analizi ve replication lag yönetimi, reactive değil proactive bir yaklaşım gerektiriyor. Özet olarak yapmanız gerekenler:
- Düzenli oplog boyutu denetimi: En az haftada bir
rs.printReplicationInfo()çıktısını inceleyin. Oplog’un kapsadığı süre 24 saatin altına düşüyorsa boyutu artırın.
- Lag threshold alarmı: 30 saniyenin üzerindeki lag değerleri için mutlaka alert kurun. 60 saniyeyi geçen lag üretim ortamında kabul edilemez.
- Oplog trafik analizi: Hangi namespace’lerin en fazla yazma ürettiğini periyodik olarak kontrol edin ve uygulama ekibiyle gereksiz yazma işlemlerini azaltmak için çalışın.
- Secondary kapasitesini primary ile eşleyin: Secondary’nin disk I/O ve RAM kapasitesi primary’den düşük olmamalı. Özellikle RAM farkı lag’ın en yaygın nedenidir.
- Initial sync süresini planlayın: Büyük cluster’larda yeni secondary ekleme ya da kurtarma için rsync tabanlı hızlı kopyalama yöntemini prosedürlerinize dahil edin.
Oplog bir kez iyi anlaşıldığında, MongoDB’nin replication mekanizması oldukça güvenilir ve öngörülebilir hale gelir. Sorunlar genellikle oplog’un kendisinden değil, boyut yetersizliği ve uygulama davranışlarından kaynaklanır.
