Troubleshooting — Yaygın Sorunlar ve Çözümler
Giriş — Yaygın Sorunlar ve Çözümleri
Bir arabayı düşün. Motor uyarı lambası yandığında panik yapmaz, kontrol paneline bakar, hata kodunu okur ve sorunu teşhis edersin. Elasticsearch da aynı: sorun olduğunda kırmızı ışıklar yanar (cluster RED), uyarılar gelir (YELLOW), loglar dolar. Önemli olan bu sinyalleri okumayı ve doğru müdahaleyi bilmek.
Production Elasticsearch cluster'ı yönetiyorsan, er ya da geç sorunlarla karşılaşacaksın. Bu ders, en yaygın sorunları, teşhis yöntemlerini ve çözümlerini sistematik olarak ele alıyor. Her sorun için "ne oluyor → neden oluyor → nasıl çözülür" üçlüsünü takip edeceğiz.
1. Cluster Health — RED ve YELLOW
Cluster Health Nedir?
GET _cluster/health
// Yanıt:
{
"cluster_name": "production",
"status": "yellow",
"number_of_nodes": 5,
"number_of_data_nodes": 3,
"active_primary_shards": 150,
"active_shards": 250,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 50,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"active_shards_percent_as_number": 83.33
}| Durum | Anlam | Aciliyet |
|---|---|---|
| 🟢 GREEN | Tüm primary ve replica shard'lar atanmış | Sorun yok |
| 🟡 YELLOW | Tüm primary shard'lar ok, bazı replica'lar atanmamış | Orta — veri kaybı riski |
| 🔴 RED | Bazı primary shard'lar atanmamış | ACİL — veri kaybı, eksik arama sonuçları |
YELLOW Cluster — En Yaygın Senaryo
Belirti: Cluster yellow, unassigned_shards > 0
En sık neden: Tek node'lu cluster'da replica var.
// Sorun teşhisi
GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state
// Çıktı:
index shard prirep state unassigned.reason
logs-2024.01 0 p STARTED
logs-2024.01 0 r UNASSIGNED INDEX_CREATEDÇözüm 1: Node ekle (doğru çözüm)
Çözüm 2: Replica'yı 0 yap (geçici, tek node'luk ortam):
PUT logs-2024.01/_settings
{
"index": {
"number_of_replicas": 0
}
}
// Tüm index'ler için:
PUT _all/_settings
{
"index": {
"number_of_replicas": 0
}
}RED Cluster — Acil Müdahale
Belirti: Cluster red, bazı aramalar eksik sonuç dönüyor veya hata veriyor.
Teşhis adımları:
// 1. Hangi index'ler RED?
GET _cat/indices?v&health=red
// 2. Hangi shard'lar unassigned?
GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state:desc
// 3. Neden atanmadı?
GET _cluster/allocation/explain
{
"index": "logs-2024.01.15",
"shard": 0,
"primary": true
}_cluster/allocation/explain çok değerli bir API — tam olarak neden bir shard'ın atanamadığını söyler:
// Örnek yanıt:
{
"index": "logs-2024.01.15",
"shard": 0,
"primary": true,
"current_state": "unassigned",
"unassigned_info": {
"reason": "NODE_LEFT",
"at": "2024-01-15T10:30:00.000Z",
"last_allocation_status": "no_valid_shard_copy"
},
"can_allocate": "no",
"allocate_explanation": "cannot allocate because all found copies of the shard are stale or corrupt",
"node_allocation_decisions": [
{
"node_name": "data-node-2",
"deciders": [
{
"decider": "disk_threshold",
"decision": "NO",
"explanation": "the node is above the high watermark [90%]"
}
]
}
]
}2. Unassigned Shards — Detaylı Çözümler
Unassigned shard'ların birçok nedeni olabilir. Her neden için farklı çözüm:
Neden 1: INDEX_CREATED — Yeni Index, Atanacak Node Yok
// Çözüm: Node ekle veya replica azalt
PUT my_index/_settings
{
"index.number_of_replicas": 0
}Neden 2: NODE_LEFT — Node Cluster'dan Ayrıldı
// Önce delayed allocation bekle (varsayılan 1 dakika)
// Node geri gelirse shard'lar otomatik atanır
// Bekleme süresini kontrol et:
GET my_index/_settings?filter_path=**.unassigned.node_left.delayed_timeout
// Acil müdahale: Reroute ile boş shard'ı yeniden ata
POST _cluster/reroute
{
"commands": [
{
"allocate_stale_primary": {
"index": "logs-2024.01.15",
"shard": 0,
"node": "data-node-2",
"accept_data_loss": true
}
}
]
}⚠️ Dikkat: allocate_stale_primary ile accept_data_loss: true kullanmak, eski (stale) bir shard kopyasını primary yapmanız demektir. Bu, en son yazılan bazı verilerin kaybolmasına neden olabilir. Başka çare kalmadığında son çare olarak kullanın.
Neden 3: ALLOCATION_FAILED — Atama Denemesi Başarısız
// Retry sınırına ulaşmış olabilir
// Retry sayısını sıfırla:
POST _cluster/reroute?retry_failed=trueNeden 4: Disk Watermark Aşıldı
// Disk kullanımını kontrol et:
GET _cat/allocation?v&h=node,disk.percent,disk.used,disk.avail,disk.total
// Çıktı:
node disk.percent disk.used disk.avail disk.total
data-node-1 87 174gb 26gb 200gb
data-node-2 92 184gb 16gb 200gb
data-node-3 78 156gb 44gb 200gbDisk watermark'ları (bkz. Bölüm 3 bu dersin ilerisi).
Neden 5: Shard Allocation Filter
// Index'te allocation filter var mı kontrol et:
GET my_index/_settings?filter_path=**.routing
// Çözüm: Yanlış filter'ı kaldır
PUT my_index/_settings
{
"index.routing.allocation.require._name": null,
"index.routing.allocation.include._name": null,
"index.routing.allocation.exclude._name": null
}Toplu Unassigned Shard Çözümü — Script
#!/bin/bash
# fix_unassigned.sh — Unassigned shard'ları teşhis et
echo "=== Unassigned Shard Raporu ==="
# Toplam sayı
TOTAL=$(curl -s 'localhost:9200/_cluster/health' | jq '.unassigned_shards')
echo "Toplam unassigned shard: $TOTAL"
# Neden dağılımı
echo -e "\n--- Sebep Dağılımı ---"
curl -s 'localhost:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason' | \
grep UNASSIGNED | awk '{print $5}' | sort | uniq -c | sort -rn
# İlk 5 index
echo -e "\n--- En çok unassigned shard olan index'ler ---"
curl -s 'localhost:9200/_cat/shards?h=index,state' | \
grep UNASSIGNED | awk '{print $1}' | sort | uniq -c | sort -rn | head -53. Disk Watermark Sorunları
Watermark Seviyeleri
Elasticsearch, disk dolduğunda otomatik önlem alır:
| Seviye | Varsayılan | Davranış |
|---|---|---|
| Low watermark | %85 | Yeni shard'lar bu node'a atanmaz |
| High watermark | %90 | Shard'lar bu node'dan başka node'lara taşınır |
| Flood stage | %95 | Index'ler read-only yapılır! |
Flood Stage — En Tehlikeli Durum
Disk %95'i aştığında Elasticsearch index'leri read_only_allow_delete moduna alır. Yazma işlemleri durur!
// Belirti: Yazma hatası
{
"error": {
"type": "cluster_block_exception",
"reason": "index [logs-2024.01.15] blocked by: [FORBIDDEN/12/index read-only / allow delete (api)]"
}
}Çözüm:
// 1. Disk alanı aç (eski index'leri sil, log temizle)
DELETE logs-2024.01.01
// 2. Read-only bloğu kaldır
PUT _all/_settings
{
"index.blocks.read_only_allow_delete": null
}
// Veya belirli index için:
PUT logs-2024.01.15/_settings
{
"index.blocks.read_only_allow_delete": null
}Watermark Ayarlarını Özelleştirme
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": "85%",
"cluster.routing.allocation.disk.watermark.high": "90%",
"cluster.routing.allocation.disk.watermark.flood_stage": "95%",
"cluster.info.update.interval": "30s"
}
}
// Veya byte cinsinden:
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": "50gb",
"cluster.routing.allocation.disk.watermark.high": "20gb",
"cluster.routing.allocation.disk.watermark.flood_stage": "10gb"
}
}💡 İpucu: Yüzde yerine mutlak değer (GB) kullanmak genellikle daha öngörülebilir. 1TB diskle %85 = 150GB boş, ama 200GB diskle %85 = 30GB boş — aynı yüzde, çok farklı sonuçlar.
4. Circuit Breaker — Bellek Koruma Mekanizması
Circuit Breaker Nedir?
Elasticsearch, bir işlem çok fazla bellek tükettiğinde OutOfMemoryError yerine o işlemi reddeder. Bunu elektrik sigortası gibi düşün: aşırı akım geldiğinde sigorta atar, ev yangınını önler.
// Belirti:
{
"error": {
"type": "circuit_breaking_exception",
"reason": "[parent] Data too large, data for [<http_request>] would be [31.2gb/32gb], which is larger than the limit of [30.4gb/32gb]"
}
}Circuit Breaker Tipleri
| Breaker | Varsayılan Limit | Ne Korur? |
|---|---|---|
| Parent | JVM heap'in %95'i | Tüm breaker'ların toplamı |
| Field data | JVM heap'in %40'ı | Field data cache (aggregation, sort) |
| Request | JVM heap'in %60'ı | Tek bir request'in bellek kullanımı |
| In-flight requests | JVM heap'in %100'ü | Gelen HTTP request'lerin toplam boyutu |
| Accounting | JVM heap'in %100'ü | Lucene segment metadata |
Parent Circuit Breaker
En sık karşılaşılan breaker. Tüm bellek kullanımının toplamını kontrol eder:
// Mevcut breaker durumlarını gör
GET _nodes/stats/breaker
// Yanıt:
{
"nodes": {
"node-1": {
"breakers": {
"parent": {
"limit_size_in_bytes": 31138512896,
"estimated_size_in_bytes": 28024661606,
"overhead": 1.0,
"tripped": 5
},
"fielddata": {
"limit_size_in_bytes": 12455405158,
"estimated_size_in_bytes": 8589934592,
"overhead": 1.03,
"tripped": 2
},
"request": {
"limit_size_in_bytes": 18683107737,
"estimated_size_in_bytes": 0,
"overhead": 1.0,
"tripped": 0
}
}
}
}
}tripped sayısı sıfırdan büyükse, o breaker çalışmış demektir.
Field Data Circuit Breaker
Text field üzerinde aggregation veya sort yapmak field data'yı belleğe yükler:
// Kötü sorgu — text field üzerinde sort
GET logs-*/_search
{
"sort": [{ "message": "asc" }]
}
// Bu, message field'ının tüm unique değerlerini belleğe yükler!
// Çözüm: Keyword alt-field kullan
GET logs-*/_search
{
"sort": [{ "message.keyword": "asc" }]
}// Field data cache'i temizle (acil durum)
POST _cache/clear?fielddata=true
// Belirli index için:
POST logs-*/_cache/clear?fielddata=trueCircuit Breaker Ayarlarını Özelleştirme
PUT _cluster/settings
{
"persistent": {
"indices.breaker.total.limit": "95%",
"indices.breaker.fielddata.limit": "40%",
"indices.breaker.request.limit": "60%"
}
}⚠️ Dikkat: Breaker limitlerini yükseltmek sorunu çözmez, sadece maskeler. Asıl çözüm: sorguyu optimize et, heap'i artır veya node ekle.
5. GC Pressure — Garbage Collection Sorunları
GC Pressure Nedir?
Java'nın çöp toplayıcısı (GC) kullanılmayan bellek alanlarını geri kazanır. Ama heap çok doluysa, GC sürekli çalışır ve Elasticsearch'ü durdurur (stop-the-world pause).
Bunu şöyle düşün: odanı toparlamaya çalışıyorsun ama sürekli yeni eşya geliyor. Bir noktada her şeyi bırakıp sadece toparlama yapman gerekiyor — bu sırada hiçbir iş yapamıyorsun.
Belirtiler
Yavaş response'lar (normalde ms olan sorgular saniyelerce sürüyor)
Node'un cluster'dan düşmesi (master timeout)
Log'larda uzun GC pause'ları
# Elasticsearch log'larında GC uyarıları:
[gc][old][123456][4] duration [15.2s], collections [1]/[15.3s], ...Teşhis
// JVM bellek kullanımı
GET _nodes/stats/jvm
// Yanıt:
{
"nodes": {
"node-1": {
"jvm": {
"mem": {
"heap_used_in_bytes": 28991029248,
"heap_used_percent": 90,
"heap_max_in_bytes": 32212254720
},
"gc": {
"collectors": {
"old": {
"collection_count": 150,
"collection_time_in_millis": 45000
},
"young": {
"collection_count": 50000,
"collection_time_in_millis": 120000
}
}
}
}
}
}
}Tehlike işaretleri:
heap_used_percentsürekli > 75%Old GC
collection_timesürekli artıyorOld GC
collection_counthızla artıyor
Çözümler
1. Heap boyutunu kontrol et:
# jvm.options — Heap boyutu
-Xms16g
-Xmx16g
# Kural: Fiziksel RAM'in yarısı, max 31GB
# 64 GB RAM → -Xmx31g (compressed oops sınırı)
# 32 GB RAM → -Xmx16g
# 16 GB RAM → -Xmx8g⚠️ Dikkat: Heap'i 32GB'ın üstüne çıkarmayın! Java'nın compressed oops optimizasyonu 32GB sınırında devre dışı kalır ve bellek kullanımı paradoks olarak artar.
2. Bellek tüketen sorguları bul:
// Hot threads — hangi thread'ler CPU/memory yiyor?
GET _nodes/hot_threads
// Hangi index'ler çok bellek kullanıyor?
GET _cat/segments?v&h=index,docs.count,size,memory&s=memory:desc3. Field data temizle:
POST _cache/clear?fielddata=true4. Gereksiz index'leri kapat veya sil:
// Eski index'leri kapat (bellek serbest kalır)
POST logs-2023.*/_close
// Veya sil
DELETE logs-2023.01.*6. Slow Query — Yavaş Sorgular
Slow Log Etkinleştirme
// Index seviyesinde slow log
PUT logs-*/_settings
{
"index.search.slowlog.threshold.query.warn": "10s",
"index.search.slowlog.threshold.query.info": "5s",
"index.search.slowlog.threshold.query.debug": "2s",
"index.search.slowlog.threshold.query.trace": "500ms",
"index.search.slowlog.threshold.fetch.warn": "1s",
"index.search.slowlog.threshold.fetch.info": "800ms",
"index.search.slowlog.level": "info",
"index.indexing.slowlog.threshold.index.warn": "10s",
"index.indexing.slowlog.threshold.index.info": "5s"
}Log çıktısı (/var/log/elasticsearch/<cluster>_index_search_slowlog.json):
{
"type": "index_search_slowlog",
"timestamp": "2024-01-15T14:30:00.000Z",
"level": "WARN",
"message": "[logs-2024.01.15][0] took[12.5s], took_millis[12500], total_hits[1500000], source[{\"query\":{\"wildcard\":{\"message\":{\"value\":\"*error*\"}}}}]"
}Query Profiling
// Sorgunun nerede zaman harcadığını gör
GET logs-2024.01.15/_search
{
"profile": true,
"query": {
"bool": {
"must": [
{ "match": { "message": "error" } },
{ "range": { "@timestamp": { "gte": "now-1h" } } }
]
}
}
}Profile çıktısı hangi query'nin, hangi shard'da, kaç ms sürdüğünü gösterir.
Yaygın Yavaş Sorgu Nedenleri ve Çözümleri
| Sorun | Neden | Çözüm |
|---|---|---|
wildcard("*error*") | Leading wildcard tüm terimleri tarar | match veya ngram analyzer kullan |
script_score her doc'ta | Her document'ta script çalışır | function_score ile sadece match'lerde çalıştır |
Büyük from/size | Deep pagination | search_after veya scroll kullan |
| Çok fazla shard | Her shard'a istek gider | Shard sayısını azalt, routing kullan |
text field'da sort | Field data belleğe yüklenir | keyword alt-field kullan |
| Regex query | Pahalı — tüm terimleri kontrol eder | Daha spesifik query kullan |
// KÖTÜ — leading wildcard
GET logs-*/_search
{
"query": {
"wildcard": { "url": { "value": "*login*" } }
}
}
// İYİ — match query
GET logs-*/_search
{
"query": {
"match": { "url": "login" }
}
}7. Rejected Thread Pool — İş Parçacığı Reddedilmesi
Thread Pool Nedir?
Elasticsearch farklı iş tipleri için ayrı thread pool'lar kullanır:
GET _cat/thread_pool?v&h=node_name,name,active,rejected,queue,completed&s=rejected:desc
// Çıktı:
node_name name active rejected queue completed
data-node-1 search 10 1523 0 5000000
data-node-1 write 5 892 0 3000000
data-node-2 search 8 45 0 4500000Thread Pool Tipleri
| Pool | Kullanım | Size | Queue |
|---|---|---|---|
| search | Arama sorguları | CPU çekirdek * 3/2 + 1 | 1000 |
| write | Index/update/delete/bulk | CPU çekirdek | 10000 |
| get | Get API | CPU çekirdek | 1000 |
| analyze | Analyze API | 1 | 16 |
| management | Cluster yönetimi | 5 | - |
Rejected — Ne Anlama Gelir?
Thread pool dolu ve queue da dolu — gelen istek reddedilir. Client tarafında 429 Too Many Requests veya EsRejectedExecutionException hatası alırsınız.
Çözümler
1. Search rejected yüksekse:
// Sorguları optimize et (slow log'a bak)
// Shard sayısını azalt (daha az parallel iş)
// Node ekle (load distribution)
// Coordinating-only node ekle (arama load'u dağıt)2. Write rejected yüksekse:
// Bulk size'ı küçült (5-15 MB arası optimal)
// Yazma paralelliğini azalt
// Refresh interval'ı artır (yazma sırasında segment oluşturma azalır)
PUT my_index/_settings
{
"index.refresh_interval": "30s"
}
// Replica'ları geçici olarak 0'a çek (yazma hızını artırır)
PUT my_index/_settings
{
"index.number_of_replicas": 0
}3. Queue boyutunu artır (geçici çözüm):
# elasticsearch.yml
thread_pool.search.queue_size: 2000
thread_pool.write.queue_size: 20000⚠️ Dikkat: Queue boyutunu artırmak, reddedilme yerine bekletme sağlar ama bellek tüketir. Asıl çözüm: load'u azalt veya kapasite artır.
8. Mapping Explosion
Sorun
Dynamic mapping açıkken, her yeni field otomatik oluşturulur. Eğer verilerinizde binlerce farklı field geliyorsa (örneğin key-value logları), mapping devasa büyür:
// Belirti: Cluster yavaşlıyor, mapping güncelleme süresi artar
GET my_index/_mapping
// ... 50.000 field döner 😱Neden Tehlikeli?
Her field cluster state'te saklanır ve tüm node'lara replike edilir
Cluster state büyüdükçe master node yavaşlar
Mapping güncelleme işlemi cluster-wide lock alır
Çözüm 1: Field Sayısı Limiti
PUT my_index/_settings
{
"index.mapping.total_fields.limit": 2000
}
// Varsayılan: 1000. Çok yüksek yapma!Çözüm 2: Dynamic Mapping Kontrolü
// Dynamic mapping'i kapat
PUT my_index/_mapping
{
"dynamic": "strict"
}
// Veya bilinmeyen field'ları yoksay (index'leme)
PUT my_index/_mapping
{
"dynamic": "false"
}Çözüm 3: Flattened Field Type
Key-value veri için ideal — tüm alt field'ları tek field olarak saklar:
PUT my_index
{
"mappings": {
"properties": {
"labels": {
"type": "flattened"
}
}
}
}
// Artık labels altında ne gelirse gelsin tek field:
POST my_index/_doc
{
"labels": {
"env": "production",
"app": "api-gateway",
"version": "2.1.0",
"region": "eu-west-1"
}
}9. too_many_clauses — Bool Query Patlaması
Sorun
// Hata:
{
"error": {
"type": "too_many_clauses",
"reason": "maxClauseCount is set to 4096"
}
}Bu genellikle wildcard/prefix query'lerin çok fazla terime genişlemesinden kaynaklanır:
// KÖTÜ — Binlerce terime genişler
GET logs-*/_search
{
"query": {
"bool": {
"should": [
{ "prefix": { "url.keyword": "/api/v" } }
// Bu prefix binlerce farklı URL'e match edebilir
]
}
}
}Çözümler
1. Limiti artır (geçici):
PUT _cluster/settings
{
"persistent": {
"indices.query.bool.max_clause_count": 8192
}
}2. Sorguyu optimize et (kalıcı):
// prefix yerine match_phrase_prefix kullan
GET logs-*/_search
{
"query": {
"match_phrase_prefix": {
"url": "/api/v"
}
}
}
// Veya terms query ile spesifik değerler ver
GET logs-*/_search
{
"query": {
"terms": {
"status_code": [500, 502, 503, 504]
}
}
}10. Shard Allocation Sorunları
Shard Allocation Neden Bekliyor?
// Detaylı açıklama al
GET _cluster/allocation/explain
// Belirli bir shard için:
GET _cluster/allocation/explain
{
"index": "my_index",
"shard": 0,
"primary": true
}Yaygın Allocation Sorunları
1. Awareness attribute uyuşmazlığı:
// Rack awareness aktifse ve yeterli rack yoksa
// replica, primary ile aynı rack'e atanamaz
// Geçici çözüm:
PUT _cluster/settings
{
"transient": {
"cluster.routing.allocation.awareness.attributes": ""
}
}2. Allocation filter engeli:
// Index seviyesinde filter var mı?
GET my_index/_settings?filter_path=**.routing.allocation
// Cluster seviyesinde?
GET _cluster/settings?filter_path=**.allocation3. Maximum shards per node:
// Varsayılan: node başına 1000 shard
GET _cluster/settings?filter_path=**.total_shards_per_node
// Artır (dikkatli!):
PUT _cluster/settings
{
"persistent": {
"cluster.max_shards_per_node": 1500
}
}
// Shard sayısını kontrol et:
GET _cat/allocation?v4. Shard'ı manuel taşıma:
POST _cluster/reroute
{
"commands": [
{
"move": {
"index": "logs-2024.01.15",
"shard": 2,
"from_node": "data-node-1",
"to_node": "data-node-3"
}
}
]
}11. Teşhis Araç Kutusu
Hızlı Sağlık Kontrolü
// 1. Cluster genel durum
GET _cluster/health?pretty
// 2. Node'ların durumu
GET _cat/nodes?v&h=name,heap.percent,ram.percent,cpu,load_1m,disk.used_percent,node.role
// Çıktı:
name heap.percent ram.percent cpu load_1m disk.used_percent node.role
data-node-1 72 85 45 3.20 78 d
data-node-2 68 80 38 2.80 82 d
master-1 35 60 10 0.50 25 m
// 3. Index sağlığı
GET _cat/indices?v&h=health,index,pri,rep,docs.count,store.size&s=health:desc
// 4. Shard dağılımı
GET _cat/shards?v&h=index,shard,prirep,state,node,docs,store&s=state
// 5. Pending tasks (master node queue)
GET _cat/pending_tasks?vDetaylı Teşhis
// Hot threads — CPU'yu ne yiyor?
GET _nodes/hot_threads?threads=5
// Task management — uzun süren işlemler
GET _tasks?actions=*search*&detailed=true
// Belirli bir uzun task'i iptal et
POST _tasks/node-1:12345/_cancel
// Node istatistikleri
GET _nodes/stats/indices,jvm,os,process,thread_pool
// Cluster state boyutu (mapping explosion tespiti)
GET _cluster/state?filter_path=metadata.indices.*.mappingsJava ile Health Check
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
import co.elastic.clients.elasticsearch.cat.*;
public class ClusterHealthChecker {
private final ElasticsearchClient client;
public ClusterHealthChecker(ElasticsearchClient client) {
this.client = client;
}
public void fullHealthCheck() throws Exception {
// 1. Cluster health
HealthResponse health = client.cluster().health();
System.out.printf("Cluster: %s | Status: %s | Nodes: %d%n",
health.clusterName(), health.status(), health.numberOfNodes());
System.out.printf("Shards - Active: %d | Unassigned: %d%n",
health.activeShards(), health.unassignedShards());
// 2. RED/YELLOW ise uyar
if (health.status() != co.elastic.clients.elasticsearch
._types.HealthStatus.Green) {
System.out.println("⚠️ UYARI: Cluster " + health.status());
// Unassigned shard detayı
if (health.unassignedShards() > 0) {
System.out.println("Unassigned shard var — " +
"_cluster/allocation/explain kontrol et");
}
}
// 3. Node durumları
NodesResponse nodes = client.cat().nodes(n -> n
.headers("name,heap.percent,disk.used_percent,cpu")
);
nodes.valueBody().forEach(node -> {
System.out.printf("Node: %s | Heap: %s%% | Disk: %s%% | CPU: %s%%%n",
node.name(), node.heapPercent(),
node.diskUsedPercent(), node.cpu()
);
});
}
}12. Troubleshooting Flowchart
Sorunla karşılaştığında bu sırayı takip et:
Sorun var!
│
├── Cluster RED/YELLOW mu?
│ ├── GET _cluster/health
│ ├── GET _cat/shards?v (unassigned shard'ları bul)
│ └── GET _cluster/allocation/explain (neden atanmadı?)
│
├── Yavaş sorgular mı?
│ ├── Slow log etkinleştir
│ ├── profile: true ile sorgu analizi
│ └── _cat/thread_pool (search rejected?)
│
├── Yazma hataları mı?
│ ├── Disk watermark kontrol et
│ ├── _cat/thread_pool (write rejected?)
│ ├── Bulk size kontrol et (5-15 MB optimal)
│ └── Circuit breaker kontrol et
│
├── Node düşüyor mu?
│ ├── JVM heap kontrol et (> 75% tehlike)
│ ├── GC log'ları kontrol et
│ ├── Disk dolu mu?
│ └── Network sorunları? (master timeout)
│
└── Genel yavaşlık mı?
├── _nodes/hot_threads
├── _cat/nodes (CPU, heap, disk)
├── Mapping explosion? (_cluster/state boyutu)
└── Çok fazla shard? (_cat/allocation)13. Best Practices
✅ Yap
| Konu | Öneri |
|---|---|
| Monitoring | Prometheus + Grafana veya Kibana Stack Monitoring ile sürekli izle |
| Alerting | Heap > 75%, disk > 80%, RED cluster için alarm kur |
| Slow log | Production'da her zaman açık tut |
| Shard boyutu | 10-50 GB arası hedefle — çok küçük veya çok büyük yapma |
| Mapping kontrolü | dynamic: strict veya false kullan |
| Düzenli bakım | Force merge (read-only index'ler), cache temizleme |
❌ Yapma
| Konu | Neden |
|---|---|
| Heap > 31 GB | Compressed oops devre dışı kalır, bellek verimsizleşir |
| Text field sort | Field data belleğe yüklenir, circuit breaker tetiklenir |
| Leading wildcard | *error* gibi sorgular çok pahalı |
| 1000+ shard/node | Master node yavaşlar, cluster state şişer |
| Dynamic mapping kontrolsüz | Mapping explosion riski |
| Breaker limitlerini artırmak | Sorunu maskeler, çözmez |
Özet
Cluster RED/YELLOW durumunda ilk adım
_cluster/allocation/explain— bu API tam olarak neden shard atanamadığını söyler. Unassigned shard'ların en yaygın nedenleri: disk dolu, node kaybı, allocation filter.Disk watermark üç seviyedir: low (%85), high (%90), flood stage (%95). Flood stage'de index'ler read-only olur — acil disk alanı açın ve
read_only_allow_deletebloğunu kaldırın.Circuit breaker OOM'u önleyen koruma mekanizmasıdır — parent, fielddata, request ve in-flight tipleri vardır. Tetikleniyorsa sorguyu optimize edin veya heap'i artırın (max 31GB).
GC pressure heap sürekli > %75 olduğunda ortaya çıkar — node yavaşlar, hatta cluster'dan düşer. Heap boyutunu RAM'in yarısı olarak ayarlayın, 32GB sınırını aşmayın.
Slow log ve profile API yavaş sorguları teşhis eder — leading wildcard, deep pagination, text field sort en yaygın nedenlerdir.
Sistematik yaklaşım her zaman kazanır: önce
_cluster/health, sonra_cat/shards, ardından_cluster/allocation/explain. Sorunun kök nedenini bulun, semptomları değil nedeni çözün.
AI Asistan
Sorularını yanıtlamaya hazır