Elasticsearch Snapshot ile Yedekleme ve Geri Yükleme
Üretim ortamında Elasticsearch cluster’ınızın bir sabah kalkmadığını hayal edin. Disk dolmuş, node’lar split-brain yaşamış ya da yanlış bir silme işlemi tüm index’lerinizi yok etmiş. Bu noktada sizi kurtaracak tek şey düzgün çalışan bir snapshot stratejisi. Ben bu durumu bizzat yaşadım ve o günden sonra Elasticsearch yedekleme konusunu hiç hafife almıyorum.
Bu yazıda Elasticsearch Snapshot mekanizmasını baştan sona ele alacağız. Repository tanımlama, snapshot alma, zamanlama ve geri yükleme adımlarını gerçek senaryolarla işleyeceğiz. ELK Stack kullanan herkes için zorunlu okuma sayılabilecek bir konu bu.
Snapshot Nedir, Neden Önemlidir?
Elasticsearch’ün snapshot sistemi, index verilerini ve cluster metadata’sını bir repository’ye (depoya) kaydetmenizi sağlar. Bu repository bir dosya sistemi olabileceği gibi S3, GCS, Azure Blob Storage gibi uzak depolama sistemleri de olabilir.
Standart dosya kopyalama ya da disk snapshot’ı gibi yaklaşımlar Elasticsearch için güvenli değildir. Elasticsearch sürekli yazan, segment merge yapan, translog tutan bir sistem. Çalışırken dosyaları kopyalamak tutarsız veri almanıza yol açar. Snapshot API ise bunu application-consistent şekilde halleder.
Özellikle şu senaryolarda kritik öneme sahiptir:
- Veri kaybı koruması: Yanlış silme, index corruption veya disk arızası durumlarında
- Cluster migrasyonu: Elasticsearch sürüm yükseltme ya da yeni altyapıya taşıma
- Geliştirme ortamı: Üretim verisinin test ortamına güvenle aktarılması
- Uyumluluk: Log retention gereksinimleri için soğuk arşivleme
Repository Türleri ve Kurulum
Snapshot repository olarak en yaygın iki seçenek dosya sistemi (shared filesystem) ve S3’tür. Küçük ortamlar için NFS mount yeterli olsa da ciddiye aldığınız her üretim ortamında obje depolama kullanmanızı öneririm.
Shared Filesystem Repository Kurulumu
Önce tüm node’larda elasticsearch.yml dosyasına repository path’ini eklemeniz gerekiyor:
# /etc/elasticsearch/elasticsearch.yml dosyasına ekle
path.repo: ["/mnt/elasticsearch-snapshots"]
Ardından mount noktasını oluşturun ve izinleri ayarlayın:
# NFS mount noktası oluştur
mkdir -p /mnt/elasticsearch-snapshots
# NFS share'i mount et (tüm node'larda yapılmalı)
mount -t nfs nfs-server:/exports/es-snapshots /mnt/elasticsearch-snapshots
# Elasticsearch kullanıcısına sahiplik ver
chown -R elasticsearch:elasticsearch /mnt/elasticsearch-snapshots
# /etc/fstab'a ekle
echo "nfs-server:/exports/es-snapshots /mnt/elasticsearch-snapshots nfs defaults,_netdev 0 0" >> /etc/fstab
Elasticsearch’ü yeniden başlatmanıza gerek yok ama cluster rolling restart yaparsanız değişiklik aktif olur. Şimdi API ile repository’yi kaydedin:
curl -X PUT "localhost:9200/_snapshot/fs_backup"
-H 'Content-Type: application/json'
-d '{
"type": "fs",
"settings": {
"location": "/mnt/elasticsearch-snapshots",
"compress": true,
"max_restore_bytes_per_sec": "500mb",
"max_snapshot_bytes_per_sec": "200mb"
}
}'
Buradaki max_snapshot_bytes_per_sec parametresi önemli. Bunu sınırlamazsanız yoğun saatlerde snapshot işlemi cluster’ı olumsuz etkileyebilir. Bizim ortamda 200mb değeri hem makul hız hem de cluster sağlığı açısından denge noktasını yakaladı.
S3 Repository Kurulumu
S3 için önce Elasticsearch plugin’ini yüklemeniz gerekiyor:
# Plugin yükle (tüm node'larda)
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install repository-s3
# Elasticsearch'ü yeniden başlat
sudo systemctl restart elasticsearch
AWS kimlik bilgilerini keystore üzerinden güvenli şekilde ekleyin. Bunları elasticsearch.yml‘e düz metin olarak yazmak ciddi bir güvenlik açığıdır:
# Access key ekle
sudo /usr/share/elasticsearch/bin/elasticsearch-keystore add s3.client.default.access_key
# Secret key ekle
sudo /usr/share/elasticsearch/bin/elasticsearch-keystore add s3.client.default.secret_key
# Keystore'u yeniden yükle (restart gerektirmez)
curl -X POST "localhost:9200/_nodes/reload_secure_settings"
Şimdi S3 repository’sini tanımlayın:
curl -X PUT "localhost:9200/_snapshot/s3_backup"
-H 'Content-Type: application/json'
-d '{
"type": "s3",
"settings": {
"bucket": "production-es-snapshots",
"region": "eu-central-1",
"base_path": "elasticsearch/prod-cluster",
"compress": true,
"server_side_encryption": true,
"storage_class": "standard_ia",
"max_restore_bytes_per_sec": "1gb",
"max_snapshot_bytes_per_sec": "500mb"
}
}'
storage_class: standard_ia seçeneğine dikkat edin. Snapshot’larınız sık erişilecek veriler değil, disaster recovery için tutulacak arşivler. Infrequent Access sınıfı maliyeti ciddi oranda düşürür. Büyük ortamlarda bu fark aylık yüzlerce dolar olabilir.
Repository’nin düzgün çalışıp çalışmadığını doğrulayın:
curl -X POST "localhost:9200/_snapshot/s3_backup/_verify"
Snapshot Alma
Manuel Snapshot
Tüm açık index’lerin snapshot’ını almak için:
curl -X PUT "localhost:9200/_snapshot/s3_backup/snapshot_20240115_manual"
-H 'Content-Type: application/json'
-d '{
"indices": "*",
"ignore_unavailable": true,
"include_global_state": false,
"metadata": {
"taken_by": "ops-team",
"reason": "pre-upgrade backup"
}
}'
include_global_state: false ayarı önemli. Global state içinde persistent cluster settings, index templates, ingest pipeline’ları gibi şeyler var. Bunları restore ederken mevcut konfigürasyonunuzla çakışma yaratabilir. Genellikle sadece veriyi restore etmek istiyorsunuz.
ignore_unavailable: true ise red state’teki index’lerin snapshot’ı başarısız yapmasını engeller. Üretimde bu tercih edilir çünkü bazı index’ler geçici olarak erişilemez durumda olabilir.
Snapshot işleminin durumunu takip etmek için:
# Anlık durum
curl -X GET "localhost:9200/_snapshot/s3_backup/snapshot_20240115_manual"
# Aktif snapshot işlemleri
curl -X GET "localhost:9200/_snapshot/_status"
Büyük bir cluster’da bu işlem saatler sürebilir. Snapshot API asenkron çalışır, yani curl komutu hemen döner ama arka planda işlem devam eder.
Belirli Index’lerin Snapshot’ı
Tüm veriyi yedeklemek her zaman mantıklı değil. Özellikle zaman bazlı index’lerde (loglar gibi) seçici olmak hem maliyet hem de hız açısından avantajlı:
curl -X PUT "localhost:9200/_snapshot/s3_backup/snapshot_logs_20240115"
-H 'Content-Type: application/json'
-d '{
"indices": "logs-*,filebeat-*,-logs-2022-*",
"ignore_unavailable": true,
"include_global_state": false
}'
Burada logs-2022-* index’lerini dışarıda bırakıyorum. Eski yıla ait logları ayrı bir arşiv stratejisiyle yönetmek daha mantıklı.
Snapshot Lifecycle Management (SLM)
Manuel snapshot almak kabul edilemez bir yaklaşım. SLM (Snapshot Lifecycle Management) bu süreci otomatize eder ve eski snapshot’ları temizler. Elasticsearch 7.4 ile birlikte geldi, üretimde kullanmanızı kesinlikle öneririm.
curl -X PUT "localhost:9200/_slm/policy/nightly-snapshots"
-H 'Content-Type: application/json'
-d '{
"schedule": "0 30 2 * * ?",
"name": "<nightly-{now/d}>",
"repository": "s3_backup",
"config": {
"indices": ["*"],
"ignore_unavailable": true,
"include_global_state": false
},
"retention": {
"expire_after": "30d",
"min_count": 5,
"max_count": 50
}
}'
Schedule alanı Quartz cron formatında. 0 30 2 ? gece 02:30’da çalışır, yük açısından sakin bir saat. {now/d} ile tarih otomatik snapshot ismine eklenir.
Retention politikası üç parametreyle kontrol edilir:
- expire_after: Snapshot’ın maksimum yaşı. 30 günden eski snapshot’lar silinir.
- min_count: Ne kadar eski olursa olsun minimum bu kadar snapshot tutulur. Ağ kesintisi vb. durumlarda bu garantiyi sağlar.
- max_count: Maksimum snapshot sayısı. Disk/maliyet kontrolü için önemli.
Policy’yi hemen tetiklemek ve test etmek için:
# Anında çalıştır
curl -X POST "localhost:9200/_slm/policy/nightly-snapshots/_execute"
# Policy durumunu kontrol et
curl -X GET "localhost:9200/_slm/policy/nightly-snapshots"
# SLM genel durum
curl -X GET "localhost:9200/_slm/stats"
Snapshot’tan Geri Yükleme
İşte kritik kısım. Snapshot almak göreceli kolay; asıl mesele stres altında hızlı ve doğru geri yükleme yapabilmek.
Mevcut Snapshot’ları Listeleme
# Tüm snapshot'ları listele
curl -X GET "localhost:9200/_snapshot/s3_backup/_all"
# Belirli snapshot detayı
curl -X GET "localhost:9200/_snapshot/s3_backup/nightly-2024-01-15"
# Snapshot içeriğini görüntüle
curl -X GET "localhost:9200/_snapshot/s3_backup/nightly-2024-01-15/_status"
Index Restore
Bir index’i restore etmeden önce eğer cluster’da aynı isimde açık bir index varsa onu kapatmanız ya da silmeniz gerekiyor. Bu adım sıklıkla atlanıyor ve hata alınıyor.
# Önce mevcut index'i kapat
curl -X POST "localhost:9200/logs-2024-01-15/_close"
# Restore et
curl -X POST "localhost:9200/_snapshot/s3_backup/nightly-2024-01-15/_restore"
-H 'Content-Type: application/json'
-d '{
"indices": "logs-2024-01-15",
"ignore_unavailable": true,
"include_global_state": false,
"rename_pattern": "logs-(.+)",
"rename_replacement": "restored-logs-$1",
"include_aliases": false
}'
rename_pattern ve rename_replacement parametreleri altın değerinde. Mevcut index’i silmeden ya da kapatmadan, farklı isimde restore edip içeriği doğrulayabilirsiniz. Bu özellikle “yanlışlıkla silinen birkaç dokümanı kurtarmam lazım” durumlarında hayat kurtarır.
Restore işleminin ilerleyişini izlemek için:
curl -X GET "localhost:9200/_cat/recovery?v&active_only=true"
Cluster Genelinde Tam Restore
Bu senaryo daha nadirdir ama en kritik olanıdır. Yeni bir cluster’a tüm veriyi restore etmek için:
# Önce hedef cluster'da repository'yi tanımla
curl -X PUT "localhost:9200/_snapshot/s3_backup"
-H 'Content-Type: application/json'
-d '{
"type": "s3",
"settings": {
"bucket": "production-es-snapshots",
"region": "eu-central-1",
"base_path": "elasticsearch/prod-cluster",
"readonly": true
}
}'
readonly: true parametresine dikkat edin. Restore yaparken kaynak repository’yi read-only olarak tanımlamak veri bütünlüğü açısından kritik. Yeni cluster yanlışlıkla bu repository’ye yazmamalı.
# Tüm index'leri restore et
curl -X POST "localhost:9200/_snapshot/s3_backup/nightly-2024-01-15/_restore"
-H 'Content-Type: application/json'
-d '{
"indices": "*",
"ignore_unavailable": true,
"include_global_state": false,
"index_settings": {
"index.number_of_replicas": 0
},
"ignore_index_settings": [
"index.refresh_interval"
]
}'
index.number_of_replicas: 0 ile restore başlangıcında replica’ları devre dışı bırakıyoruz. Bu restore hızını önemli ölçüde artırır. Veri tamamen gelince replica sayısını normal değerine döndürün.
Yedekleme Stratejisi: Gerçek Dünya Yaklaşımı
Üretim ortamımda uyguladığım katmanlı strateji şu şekilde:
Günlük snapshot: SLM ile gece 02:30’da, 30 gün saklama. Tüm aktif index’ler dahil.
Haftalık snapshot: Her Pazar 03:00’da, 12 hafta saklama. Ayrı bir “weekly” policy adı altında.
Aylık arşiv: Her ayın 1’inde S3 Glacier’a aktarım. Script ile otomatize edilmiş, 2 yıl saklama.
Zaman bazlı log index’leri için ayrı bir yaklaşım kullanıyorum. Loglar büyüdükçe snapshot boyutu da büyür. Bu yüzden 7 günden eski log index’lerini ILM (Index Lifecycle Management) ile frozen state’e alıp ayrı bir cold repository’de saklıyorum. SLM snapshot’ı ise sadece hot ve warm state index’leri kapsıyor.
Snapshot Boyutunu Optimize Etme
İncrementel snapshot mekanizması sayesinde Elasticsearch her seferinde sadece değişen segment’leri yazar. İlk snapshot büyük olur, sonrakiler küçük. Ama yine de dikkat edilmesi gereken noktalar var:
Sık force merge yapılan ortamlarda segment’ler yeniden oluşturulduğu için snapshot boyutları beklenenden büyük çıkabilir. Bunu yaşadık. Force merge sonrası segment sayısı azalır ama mevcut snapshot ile fark büyür.
# Snapshot repository disk kullanımını kontrol et
curl -X GET "localhost:9200/_snapshot/s3_backup/_all?verbose=false"
# Snapshot istatistikleri
curl -X GET "localhost:9200/_snapshot/s3_backup/nightly-2024-01-15/_status" |
python3 -m json.tool | grep -E '"size|"file_count'
İzleme ve Alarm
Snapshot başarısız olduğunda kimsenin haberi olmadan günler geçebilir. Bunu önlemek için monitoring şart:
# Son snapshot durumunu kontrol et
curl -s "localhost:9200/_slm/policy/nightly-snapshots" |
python3 -c "
import sys, json
data = json.load(sys.stdin)
policy = data['nightly-snapshots']
last_success = policy.get('last_success', {})
last_failure = policy.get('last_failure', {})
print('Last Success:', last_success.get('snapshot_name', 'None'))
print('Last Failure:', last_failure.get('snapshot_name', 'None'))
print('Failure Reason:', last_failure.get('details', 'None'))
"
Bu kontrolü cron ile çalıştırıp sonucu Slack ya da PagerDuty’ye gönderin. Snapshot başarısızlıklarını P2 incident olarak ele alın. Bakın bugün değil ama bir gün o snapshot’a ihtiyacınız olacak, garantisi var.
Kibana kullanıyorsanız Stack Management altındaki Snapshot and Restore bölümünden görsel olarak da takip edebilirsiniz. SLM policy’lerinin durumu, son başarılı ve başarısız snapshot’lar burada görünür.
Sık Karşılaşılan Sorunlar
Repository doğrulama hatası: Genellikle izin sorunu. elasticsearch kullanıcısının NFS mount’a ya da S3 bucket’a erişimi olmayabilir.
Snapshot durumu PARTIAL: Bazı shard’lar snapshot alınamadı demek. ignore_unavailable: true olsa bile bazı durumlarda kısmen başarısız olabilir. _status endpoint’ini detaylı inceleyin, hangi shard’ların sorun çıkardığını görün.
Restore sırasında “index already exists” hatası: Açık index’i kapatmayı unuttunuz. POST /index_adı/_close ile kapatıp tekrar deneyin.
Yavaş restore hızı: max_restore_bytes_per_sec değerini geçici olarak artırın. Restore acil ise bu sınırı kaldırabilirsiniz.
# Dinamik olarak restore hızını artır
curl -X PUT "localhost:9200/_snapshot/s3_backup/_settings"
-H 'Content-Type: application/json'
-d '{
"max_restore_bytes_per_sec": "2gb"
}'
Sonuç
Elasticsearch snapshot’ı kurmak bir günlük iş, ama doğru yapmamak aylar sonra sizi çok zor durumda bırakabilir. Benim önerilerim şunlar: S3 ya da muadili obje depolama kullanın, SLM ile otomatize edin, retention politikanızı iş gereksinimlerine göre belirleyin, ve en önemlisi ayda en az bir kez gerçek restore testi yapın.
Restore testi konusunu özellikle vurguluyorum. Çoğu ekip snapshot alıyor ama hiç test restore yapmıyor. Test ortamında her ay yeni bir cluster ayağa kaldırıp snapshot’tan restore edin. Hem prosedürü öğrenmiş olursunuz hem de snapshot’larınızın gerçekten çalışıp çalışmadığını anlarsınız.
Bir felaket anında panikle ekrana bakmak yerine, daha önce defalarca yaptığınız bir işlemi sakin şekilde uygulamak ne kadar değerli, bunu ancak yaşayanlar bilir.
