Elasticsearch Küme Sağlığı İzleme ve Sorun Giderme
Gece 02:00’de telefonun çaldığını ve ekranda “ES cluster red” yazan bir alarm mesajı gördüğünü hayal et. İşte bu yazı tam o an için. Elasticsearch kümesi yönetmek, özellikle production ortamında, sürekli dikkat ve proaktif izleme gerektiriyor. Yıllar içinde onlarca kez bu alarmları aldım, bazılarını hızlıca çözdüm, bazılarında saatler harcadım. Öğrendiklerimi burada paylaşıyorum.
Küme Sağlık Durumunu Anlamak
Elasticsearch’ün üç renkli sağlık sistemi kulağa basit geliyor ama detaylar kritik. Green durumu her şeyin yolunda olduğunu, Yellow primary shardların atandığını ama bazı replica shardların eksik olduğunu, Red ise en az bir primary shardın atanmadığını gösteriyor.
Burada sık yapılan hata şu: Yellow’u tehlikesiz saymak. Eğer yellow durumdayken bir node daha kaybedersen, aniden red’e düşebilirsin. Yellow, bir emniyet kemerini takman gereken durumdur, tehlikeyi erteleme değil.
Temel sağlık kontrolünü şöyle yapıyoruz:
# Temel küme sağlık durumu
curl -X GET "http://localhost:9200/_cluster/health?pretty"
# Daha fazla detay için
curl -X GET "http://localhost:9200/_cluster/health?level=indices&pretty"
# Shard bazında detay
curl -X GET "http://localhost:9200/_cluster/health?level=shards&pretty"
level=shards parametresi özellikle hangi shardın sorun çıkardığını bulmak için çok işe yarıyor. Production’da bir indeks kırmızıya döndüğünde doğrudan shard seviyesine inmek zaman kazandırıyor.
Node Durumu ve Metriklerini İzlemek
Küme sağlığının ötesinde, node’ların ne durumda olduğunu düzenli kontrol etmek gerekiyor. Ben bunu iki katmanlı yapıyorum: anlık kontroller ve trend bazlı izleme.
# Tüm node'ların özet durumu
curl -X GET "http://localhost:9200/_cat/nodes?v&h=name,ip,heap.percent,ram.percent,cpu,load_1m,node.role,master"
# Node bazlı detaylı istatistikler
curl -X GET "http://localhost:9200/_nodes/stats?pretty"
# Sadece JVM ve heap bilgisi
curl -X GET "http://localhost:9200/_nodes/stats/jvm?pretty"
_cat/nodes çıktısında dikkat etmem gereken değerler şunlar:
- heap.percent: Bu %80’in üzerine çıktığında alarm vermeli. Sürekli %90+ olan node GC baskısı altında demektir ve sorguları yavaşlatır.
- cpu: Anlık spike’lar normal ama sürekli yüksek CPU, indexing veya query bottleneck’e işaret eder.
- load_1m: Elasticsearch’ün dışında da sistem kaynaklarının izlenmesi kritik.
Bir keresinde bir müşteri ortamında heap %95 sabitlendi ve kimse fark etmemişti. Cluster yavaş yavaş sorgu zaman aşımları vermeye başladı. Heap dump aldık, memory leak vardı üçüncü parti bir plugin’de. Ama monitoring olmasaydı bu durumu öğrenmemiz aylar alabilirdi.
Shard Yönetimi ve Sorunları Tespit Etmek
Unassigned shard’lar, çoğu production sorunun kaynağı. Bunları bulmak ve nedenini anlamak için:
# Atanmamış shardları listele
curl -X GET "http://localhost:9200/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state"
# Belirli bir shardın neden atanmadığını anlamak
curl -X GET "http://localhost:9200/_cluster/allocation/explain?pretty" -H 'Content-Type: application/json' -d'
{
"index": "my-index",
"shard": 0,
"primary": true
}'
allocation/explain endpoint’i gerçekten hayat kurtarıcı. Neden bu shard atanmıyor diye saatlerce uğraşmak yerine, Elasticsearch’ün kendi açıklamasını okuyorsun. Çoğunlukla disk dolu, node filter’a uymuyor veya allocation retry limit aşılmış gibi net cevaplar veriyor.
Unassigned shard sorununu çözmek için bazen retry mekanizmasını tetiklemek gerekiyor:
# Tüm unassigned shardları yeniden denemeye zorla
curl -X POST "http://localhost:9200/_cluster/reroute?retry_failed=true"
# Manuel shard atama (son çare)
curl -X POST "http://localhost:9200/_cluster/reroute?pretty" -H 'Content-Type: application/json' -d'
{
"commands": [
{
"allocate_stale_primary": {
"index": "my-index",
"shard": 0,
"node": "node-1",
"accept_data_loss": true
}
}
]
}'
accept_data_loss: true parametresini dikkatli kullan. Bu, veri kaybını kabul ettiğini beyan etmek demek. Ancak tek seçenek buysa ve stale primary varsa bunu yapmak kümeni kurtarabilir. Ben bunu bir felaketten kurtarma senaryosunda kullandım ve o anı hala hatırlıyorum, ellerin titreyerek komutu çalıştırıyorsun.
Index ve Mapping Sorunları
Index’lerin durumu küme sağlığını doğrudan etkiliyor. Hangi index’lerin sorunlu olduğunu hızlıca görmek için:
# Tüm indexlerin sağlık durumu
curl -X GET "http://localhost:9200/_cat/indices?v&h=health,status,index,pri,rep,docs.count,store.size&s=health"
# Belirli bir indexin detaylı istatistikleri
curl -X GET "http://localhost:9200/my-index/_stats?pretty"
# Index segment bilgisi - merge sorunları için
curl -X GET "http://localhost:9200/_cat/segments/my-index?v"
Segment sayısı çok fazlaysa (binler mertebesinde) arama performansı ciddi şekilde düşer. Bu durumda force merge işlemi yapılabilir ama bunu aktif yazılan index’lerde yapmak doğru değil, sadece artık yazılmayan (closed/read-only) index’lerde önerilir.
# Eski, artık yazılmayan indexlerde force merge
curl -X POST "http://localhost:9200/old-index-2024-01/_forcemerge?max_num_segments=1"
Bu işlem çok kaynak tüketir, büyük index’lerde saatler sürebilir. Production saatlerinde değil, gece yapılmalı.
Performans Sorunlarını Teşhis Etmek
Yavaş sorgular, Elasticsearch’te çoğu zaman ya yanlış mapping’den ya da yetersiz shard/replica konfigürasyonundan kaynaklanır. Ama önce slow log’u etkinleştirmek gerekiyor:
# Slow log threshold'larını ayarla
curl -X PUT "http://localhost:9200/my-index/_settings" -H 'Content-Type: application/json' -d'
{
"index.search.slowlog.threshold.query.warn": "10s",
"index.search.slowlog.threshold.query.info": "5s",
"index.search.slowlog.threshold.fetch.warn": "1s",
"index.indexing.slowlog.threshold.index.warn": "10s"
}'
Slow log Elasticsearch’ün log dizininde *_index_search_slowlog.log formatında oluşuyor. Bu logları Kibana’ya göndermek ve orada analiz etmek, hangi sorguların problem çıkardığını çok hızlı gösteriyor.
Thread pool durumuna bakmak da önemli:
# Thread pool istatistikleri
curl -X GET "http://localhost:9200/_cat/thread_pool?v&h=node_name,name,active,rejected,completed,queue"
Burada rejected değerinin 0’dan büyük olması kritik bir uyarı. Search veya write thread pool’da rejection görüyorsan, ya queue dolmuştur ya da worker sayısı yetersizdir. Bu durumda mapping optimizasyonu, shard sayısını artırma veya donanım ekleme seçeneklerini değerlendirmek gerekir.
Disk Kullanımı ve Watermark Yönetimi
Elasticsearch’ün disk watermark mekanizması çok önemli ama yeterince bilinmiyor. Disk dolduğunda cluster write işlemlerini reddeder ve bu production’da panik anlarına yol açar.
# Disk kullanım durumu
curl -X GET "http://localhost:9200/_cat/allocation?v"
# Mevcut watermark ayarlarını kontrol et
curl -X GET "http://localhost:9200/_cluster/settings?include_defaults=true&filter_path=**.watermark"
# Geçici olarak watermark threshold'unu genişlet (acil durum)
curl -X PUT "http://localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"transient": {
"cluster.routing.allocation.disk.watermark.low": "90%",
"cluster.routing.allocation.disk.watermark.high": "95%",
"cluster.routing.allocation.disk.watermark.flood_stage": "97%"
}
}'
Dikkat: Bu ayarı transient (geçici) olarak yapıyorum, persistent değil. Geçici çözümleri kalıcı hale getirme alışkanlığı uzun vadede ciddi sorunlara yol açıyor. Asıl çözüm disk kapasitesini artırmak veya eski index’leri silmek/arşivlemek olmalı.
Index lifecycle management (ILM) kullanmıyorsan, eski index’leri temizlemek için basit bir Bash scripti işe yarıyor:
#!/bin/bash
# 30 günden eski log indexlerini sil
THRESHOLD_DATE=$(date -d "30 days ago" +%Y.%m.%d)
ES_HOST="http://localhost:9200"
for index in $(curl -s "$ES_HOST/_cat/indices/logstash-*?h=index" | sort); do
INDEX_DATE=$(echo $index | grep -oP 'd{4}.d{2}.d{2}')
if [[ "$INDEX_DATE" < "$THRESHOLD_DATE" ]]; then
echo "Siliniyor: $index"
curl -X DELETE "$ES_HOST/$index"
fi
done
Bu scripti cron’a eklemeden önce önce dry-run yapıp hangi index’leri sildiğini kontrol etmeni öneririm. Yanlış index silinmesi dramatik sonuçlar doğurabilir.
Otomatik İzleme ve Alerting Kurulumu
Bunları manuel yapmak sürdürülebilir değil. Prometheus + Grafana veya Kibana Stack Monitoring kullanmak şart. Ama en azından basit bir health check scriptiyle başlanabilir:
#!/bin/bash
ES_HOST="http://localhost:9200"
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR_WEBHOOK"
ALERT_THRESHOLD_HEAP=80
# Küme sağlık kontrolü
HEALTH=$(curl -s "$ES_HOST/_cluster/health" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['status'])")
if [[ "$HEALTH" == "red" ]]; then
MESSAGE="KRITIK: Elasticsearch küme durumu RED! Hemen kontrol edilmeli."
curl -s -X POST -H 'Content-type: application/json'
--data "{"text":"$MESSAGE"}"
"$SLACK_WEBHOOK"
fi
# Heap kullanım kontrolü
HEAP_PERCENT=$(curl -s "$ES_HOST/_cat/nodes?h=heap.percent" | sort -n | tail -1 | tr -d ' ')
if [[ $HEAP_PERCENT -gt $ALERT_THRESHOLD_HEAP ]]; then
MESSAGE="UYARI: Elasticsearch heap kullanimi %$HEAP_PERCENT seviyesinde. Kontrol edilmeli."
curl -s -X POST -H 'Content-type: application/json'
--data "{"text":"$MESSAGE"}"
"$SLACK_WEBHOOK"
fi
echo "Kontrol tamamlandi. Kume durumu: $HEALTH, Max heap: %$HEAP_PERCENT"
Bu scripti /5 * cron ile çalıştırmak, en azından kritik durumları yakalamak için yeterli. Daha gelişmiş bir setup için Elastic’in kendi Stack Monitoring özelliği veya Prometheus elasticsearch_exporter + Grafana kombinasyonu çok daha kapsamlı görünürlük sağlıyor.
Sık Karşılaşılan Senaryolar ve Çözümleri
Split-brain Durumu
Discovery ayarları yanlışsa, özellikle minimum_master_nodes doğru ayarlanmamışsa, iki node aynı anda master olduğunu düşünebilir. Elasticsearch 7.x ile bu büyük ölçüde otomatik hale geldi ama eski sürümlerde ciddi bir sorundu.
# Mevcut master node'u görmek
curl -X GET "http://localhost:9200/_cat/master?v"
# Cluster state'in boyutunu kontrol et (şişmiş state sorun yaratır)
curl -X GET "http://localhost:9200/_cluster/state/metadata?pretty" | wc -c
Circuit Breaker Hataları
“Data too large” hataları genellikle circuit breaker’dan geliyor. Bu, OOM’dan koruyan bir mekanizma.
# Circuit breaker istatistikleri
curl -X GET "http://localhost:9200/_nodes/stats/breaker?pretty"
# Fielddata kullanımını görmek
curl -X GET "http://localhost:9200/_cat/fielddata?v"
Fielddata çok yüksekse, text field’larda aggregation yapılıyor olabilir. Bu mapping hatası. Text field’lar için .keyword alt field’ı kullanmak veya doc_values ile çalışmak gerekiyor.
Recovery Sürecini İzlemek
Node yeniden başlatıldıktan veya yeni bir node eklendikten sonra shard recovery sürecini izlemek önemli:
# Recovery durumunu izle
curl -X GET "http://localhost:9200/_cat/recovery?v&active_only=true"
# Detaylı recovery bilgisi
curl -X GET "http://localhost:9200/_recovery?pretty&active_only=true"
Büyük index’lerde recovery saatler sürebilir. Bu süreçte küme genellikle yellow durumunda kalır. Panikleyip node’u yeniden başlatmak recovery’yi sıfırlar ve daha uzun sürer. Sabırla izlemek gerekiyor.
Proaktif Kapasite Planlaması
Sorun çıktıktan sonra koşturmak yerine önceden önlem almak gerekiyor. Ben şu metrikleri haftalık düzenli bakıyorum:
- Disk büyüme hızı: Mevcut büyüme hızıyla kaç gün sonra disk dolacak?
- Index büyüklüğü ve shard count trendi: Çok fazla küçük shard, Elasticsearch overhead’ini artırır.
- JVM GC süresi: Yüzde olarak değil, toplam GC süresi saniye cinsinden ne kadar?
- Rejected thread pool sayısı: Bu sıfır olmak zorunda.
Bir node’un heap’ini izlerken şunu da göz önünde bulundurmak lazım: JVM heap, toplam RAM’in %50’sinden fazla olmamalı. Gerisi OS dosya sistemi cache’i için bırakılmalı. Bu denge çok önemli çünkü Elasticsearch Lucene indekslerini OS cache’e güvenerek okur.
Sonuç
Elasticsearch kümesi izlemek, bir kez kurulup unutulan bir şey değil. Cluster sağlığı, node metrikleri, shard durumu, disk kullanımı ve thread pool’lar sürekli takip edilmeli. Gece 02:00’deki alarmı almamak için gündüz proaktif önlemler alınmalı.
Özetle odaklanılması gerekenler:
- Heap yüzdesi 80’in üzerine çıkmamalı, çıkıyorsa kök neden araştırılmalı.
- Unassigned shard sıfır olmak zorunda,
allocation/explainile hızlıca teşhis edilmeli. - Disk watermark‘lar izlenmeli, dolmadan önce temizlik yapılmalı.
- Rejected thread pool değeri sıfırdan büyükse acil müdahale gerekiyor.
- Slow log etkinleştirilmeli ve düzenli analiz edilmeli.
En önemlisi, her production ortamı farklı. Bu yazıdaki komutları kör bir şekilde uygulamak yerine, kendi ortamının baseline metriklerini oluştur. Normal değerleri bilmeden anormal olanı tanıyamazsın.
