← Kursa Dön
📄 Text · 30 min

Cluster Health ve Shard Allocation

Giriş — Green/Yellow/Red ve Allocation Explain

Bir apartmanın yönetim sistemi düşün. Her dairede oturan var (primary shard), her dairenin bir de yedek anahtarı var komşuda (replica shard). Apartman yöneticisi (master node) kimin nerede oturduğunu takip eder. Herkes yerindeyse durum yeşil. Birinin yedek anahtarı kaybolmuşsa sarı — acil değil ama riskli. Birinin dairesi yanmışsa (primary shard kayıp) kırmızı — acil müdahale gerek.

Cluster health ve shard allocation, Elasticsearch yönetiminin en temel konusu. Production'da "cluster neden sarı?" sorusuna 30 saniyede cevap verebilmek olmazsa olmaz bir beceri. Bu derste bu beceriyi kazanacaksınız.


1. Cluster Health Derinlemesine

Üç Renk, Üç Anlam

GET _cluster/health
{
  "cluster_name": "production-cluster",
  "status": "yellow",
  "timed_out": false,
  "number_of_nodes": 5,
  "number_of_data_nodes": 3,
  "active_primary_shards": 45,
  "active_shards": 80,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 10,
  "delayed_unassigned_shards": 5,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 88.9
}

Her Alanın Anlamı

AlanAçıklamaEndişe Eşiği
statusGreen/Yellow/RedYellow = uyarı, Red = acil
number_of_nodesToplam node sayısıBeklenen sayıdan azsa sorun var
active_primary_shardsAktif primary shardBu 0'dan büyük olmalı
active_shardsAktif primary + replica
relocating_shardsTaşınmakta olan shard> 0 ise rebalancing var
initializing_shardsBaşlatılmakta olan shard> 0 ise recovery var
unassigned_shardsAtanmamış shard sayısı> 0 ise sorun var
delayed_unassigned_shardsGecikmeli atanmamış shardNode geçici düştüyse bekler
number_of_pending_tasksBekleyen cluster task> 50 ise master yetişemiyor
active_shards_percentAktif shard yüzdesi< 100% ise sorun var

Index Seviyesinde Health

GET _cluster/health?level=indices

// Sadece sorunlu index'ler:
GET _cluster/health?level=indices&filter_path=indices.*.status

// Belirli bir index:
GET _cluster/health/products

Shard Seviyesinde Health

GET _cluster/health/products?level=shards

// Yanıt:
{
  "cluster_name": "production-cluster",
  "status": "yellow",
  "indices": {
    "products": {
      "status": "yellow",
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "active_primary_shards": 3,
      "active_shards": 5,
      "unassigned_shards": 1,
      "shards": {
        "0": {
          "status": "green",
          "primary_active": true,
          "active_shards": 2,
          "unassigned_shards": 0
        },
        "1": {
          "status": "yellow",
          "primary_active": true,
          "active_shards": 1,
          "unassigned_shards": 1
        },
        "2": {
          "status": "green",
          "primary_active": true,
          "active_shards": 2,
          "unassigned_shards": 0
        }
      }
    }
  }
}

Buradan görüyoruz: Shard 1'in replica'sı atanmamış (yellow).


2. Shard Allocation — Shard'lar Nasıl Dağıtılır?

Allocation Kuralları

Master node, shard'ları node'lara atarken şu kurallara uyar:

  1. Aynı shard'ın primary ve replica'sı aynı node'da olamaz — yoksa node düşünce her ikisi de kaybolur

  2. Disk watermark'ları: Disk %85 doluysa yeni shard atanmaz, %90'da shard'lar taşınır

  3. Allocation awareness: Zone bazlı dağıtım yapılandırılabilir

  4. Custom allocation rules: Index bazında node filtreleme

Shard Durumları

DurumAçıklama
STARTEDAktif, çalışıyor
INITIALIZINGBaşlatılıyor (recovery)
RELOCATINGBaşka node'a taşınıyor
UNASSIGNEDHiçbir node'a atanmamış
# Shard durumlarını listele
GET _cat/shards?v&s=state

# Sadece unassigned shard'lar
GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state:asc

Unassigned Shard Sebepleri

SebepAçıklama
INDEX_CREATEDIndex yeni oluşturuldu, shard'lar henüz atanmadı
CLUSTER_RECOVEREDCluster recovery sonrası
DANGLING_INDEX_IMPORTEDDangling index import edildi
NEW_INDEX_RESTOREDSnapshot'tan restore edildi
NODE_LEFTNode cluster'dan ayrıldı
REROUTE_CANCELLEDReroute iptal edildi
REINITIALIZEDShard yeniden başlatıldı
REPLICA_ADDEDReplica sayısı artırıldı
ALLOCATION_FAILEDAtama başarısız oldu
EXISTING_INDEX_RESTOREDMevcut index üzerine restore

3. Allocation Explain — "Neden Atanmadı?"

Bu, shard allocation sorunlarını teşhis etmenin en güçlü aracı.

Otomatik Explain (İlk Atanmamış Shard)

GET _cluster/allocation/explain

// Yanıt örneği:
{
  "index": "products",
  "shard": 1,
  "primary": false,
  "current_state": "unassigned",
  "unassigned_info": {
    "reason": "NODE_LEFT",
    "at": "2024-01-15T10:30:00.000Z",
    "last_allocation_status": "no_attempt",
    "delayed": true,
    "allocation_delay_in_millis": 60000,
    "remaining_delay_in_millis": 35000
  },
  "can_allocate": "no",
  "allocate_explanation": "cannot allocate because allocation is not permitted to any of the nodes",
  "node_allocation_decisions": [
    {
      "node_id": "node-1-id",
      "node_name": "data-1",
      "transport_address": "10.0.1.10:9300",
      "node_decision": "no",
      "deciders": [
        {
          "decider": "same_shard",
          "decision": "NO",
          "explanation": "a copy of this shard is already allocated to this node"
        }
      ]
    },
    {
      "node_id": "node-2-id",
      "node_name": "data-2",
      "transport_address": "10.0.1.11:9300",
      "node_decision": "yes"
    }
  ]
}

Belirli Bir Shard İçin Explain

GET _cluster/allocation/explain
{
  "index": "products",
  "shard": 1,
  "primary": false
}

Yaygın Allocation Kararları (Deciders)

DeciderKararAnlam
same_shardNOPrimary ve replica aynı node'da olamaz
disk_thresholdNONode'un diski dolu (watermark aşılmış)
filterNOIndex allocation filter'ı bu node'u engelliyor
awarenessNOZone/rack awareness kuralı engel
max_retryNOAtama defalarca başarısız oldu
node_versionNONode versiyonu uyumsuz
throttlingTHROTTLEAynı anda çok fazla recovery — bekle

4. Shard Allocation Ayarları

Disk Watermark'ları

GET _cluster/settings?include_defaults=true&flat_settings=true&filter_path=defaults.cluster.routing.allocation.disk*

// Varsayılan değerler:
// cluster.routing.allocation.disk.watermark.low: 85%
// cluster.routing.allocation.disk.watermark.high: 90%
// cluster.routing.allocation.disk.watermark.flood_stage: 95%

// Değiştirme:
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.disk.watermark.low": "80%",
    "cluster.routing.allocation.disk.watermark.high": "85%",
    "cluster.routing.allocation.disk.watermark.flood_stage": "92%",
    "cluster.routing.allocation.disk.watermark.flood_stage.frozen": "97%"
  }
}

Watermark davranışları:

  • Low (%85): Bu eşik aşıldığında, node'a yeni shard atanmaz

  • High (%90): Bu eşik aşıldığında, shard'lar diğer node'lara taşınmaya başlar

  • Flood stage (%95): Bu eşik aşıldığında, ilgili index'ler read-only olur

Allocation Enable/Disable

// Tüm allocation'ı durdur (maintenance window)
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.enable": "none"
  }
}

// Sadece primary allocation
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.enable": "primaries"
  }
}

// Normal duruma dön
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.enable": "all"
  }
}
DeğerAçıklama
allTüm shard'lar atanabilir (varsayılan)
primariesSadece primary shard'lar atanabilir
new_primariesSadece yeni oluşturulan index'lerin primary'leri
noneHiçbir shard atanmaz

Recovery Throttling

// Aynı anda kaç shard recover edebilir
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.node_concurrent_incoming_recoveries": 2,
    "cluster.routing.allocation.node_concurrent_outgoing_recoveries": 2,
    "cluster.routing.allocation.node_concurrent_recoveries": 2,
    "indices.recovery.max_bytes_per_sec": "100mb"
  }
}

Delayed Allocation

Bir node geçici olarak düştüğünde (restart), hemen shard'ları başka yere taşımak yerine belirli bir süre beklemek daha akıllıca:

// Index bazında delayed allocation
PUT products/_settings
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "5m"
  }
}

// Cluster genelinde
PUT _all/_settings
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "10m"
  }
}

Neden? Bir node restart için 2 dakika offline kalsa, tüm shard'larını başka node'lara taşımak (ve geri geldiğinde tekrar taşımak) saatler alabilir. 5-10 dakika beklemek çoğu durumda doğru karardır.


5. Shard Allocation Filtering

Index Bazında Filtreleme

// Index'i sadece belirli node'lara ata
PUT products/_settings
{
  "index.routing.allocation.require.data_tier": "hot"
}

// Belirli node'lardan kaçın
PUT old-logs/_settings
{
  "index.routing.allocation.exclude._name": "data-hot-1,data-hot-2"
}

// Belirli IP adreslerine ata
PUT products/_settings
{
  "index.routing.allocation.include._ip": "10.0.1.10,10.0.1.11"
}

Filter Operatörleri

OperatörAçıklama
requireShard sadece bu koşulu sağlayan node'lara atanabilir
includeShard bu node'lardan birine atanabilir
excludeShard bu node'lara atanamaz

Built-in Attribute'lar

AttributeAçıklama
_nameNode adı
_host_ipHost IP adresi
_publish_ipPublish IP adresi
_ipHost veya publish IP
_hostHostname
_idNode ID
_tierData tier (hot, warm, cold, frozen)

6. Allocation Awareness — Zone ve Rack

Shard Allocation Awareness

Replica'ların primary ile farklı zone'da olmasını garanti eder:

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes": "zone"
  }
}
# Node konfigürasyonu
# data-1 (AZ-1)
node.attr.zone: az-1

# data-2 (AZ-1)
node.attr.zone: az-1

# data-3 (AZ-2)
node.attr.zone: az-2

# data-4 (AZ-2)
node.attr.zone: az-2

Bu durumda: Shard 0'ın primary'si az-1'deyse, replica'sı az-2'ye atanır. Bir zone tamamen çökse, diğer zone'daki kopya veriyi korur.

Forced Awareness

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes": "zone",
    "cluster.routing.allocation.awareness.force.zone.values": "az-1,az-2,az-3"
  }
}

force ile: Eğer tanımlı zone'lardan biri tamamen yoksa (tüm node'ları düşmüşse), o zone'a ait replica'lar atanmadan bekler — kalan zone'lara sıkıştırılmaz. Bu, bir zone geri geldiğinde veri tutarlılığını korur.


7. Manuel Shard Yönetimi — Reroute API

Shard Taşıma (Move)

POST _cluster/reroute
{
  "commands": [
    {
      "move": {
        "index": "products",
        "shard": 0,
        "from_node": "data-1",
        "to_node": "data-3"
      }
    }
  ]
}

Unassigned Shard'ı Manuel Atama

// Replica'yı belirli node'a ata
POST _cluster/reroute
{
  "commands": [
    {
      "allocate_replica": {
        "index": "products",
        "shard": 1,
        "node": "data-2"
      }
    }
  ]
}

Kayıp Primary Shard'ı Kurtarma (Veri Kaybı Riski!)

// ⚠️ DİKKAT: Bu komut veri kaybına yol açabilir!
// Sadece primary shard tamamen kaybolduğunda ve başka seçenek yoksa
POST _cluster/reroute
{
  "commands": [
    {
      "allocate_stale_primary": {
        "index": "products",
        "shard": 0,
        "node": "data-1",
        "accept_data_loss": true
      }
    }
  ]
}

// Boş primary atama (tüm veri kaybolur!)
POST _cluster/reroute
{
  "commands": [
    {
      "allocate_empty_primary": {
        "index": "products",
        "shard": 0,
        "node": "data-1",
        "accept_data_loss": true
      }
    }
  ]
}

⚠️ Dikkat: allocate_stale_primary ve allocate_empty_primary son çare olarak kullanılır. Mümkünse snapshot'tan restore edin.

Başarısız Atama Denemelerini Sıfırlama

POST _cluster/reroute?retry_failed=true

8. Rebalancing — Otomatik Dengeleme

Elasticsearch, shard'ları node'lar arasında otomatik dengeler. Ama bazen müdahale gerekir:

// Rebalancing ayarları
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.rebalance.enable": "all",
    "cluster.routing.allocation.balance.shard": 0.45,
    "cluster.routing.allocation.balance.index": 0.55,
    "cluster.routing.allocation.balance.threshold": 1.0
  }
}
AyarAçıklama
balance.shardNode'lar arası toplam shard dengesinin ağırlığı
balance.indexIndex başına shard dengesinin ağırlığı
balance.thresholdRebalancing tetikleme eşiği (düşük = daha agresif)
// Rebalancing'i geçici durdur
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.rebalance.enable": "none"
  }
}

// Tekrar aç
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.rebalance.enable": "all"
  }
}

9. Bütünleşik Örnek: "Cluster Yellow — Ne Yapmalı?"

Gerçek dünya senaryosu: Sabah geldiniz, monitoring alert vermiş — cluster yellow.

Adım 1: Genel Durum

GET _cluster/health

// Sonuç: yellow, unassigned_shards: 8

Adım 2: Hangi Index'ler Sorunlu?

GET _cat/indices?v&health=yellow&h=index,health,pri,rep,docs.count,store.size

// Çıktı:
// index          health pri rep docs.count store.size
// orders-2024.01 yellow 3   1   5000000    12gb
// logs-2024.01   yellow 5   1   25000000   45gb

Adım 3: Hangi Shard'lar Atanmamış?

GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason,node&s=state

// Çıktı:
// index          shard prirep state       unassigned.reason node
// orders-2024.01 1     r      UNASSIGNED  NODE_LEFT
// orders-2024.01 2     r      UNASSIGNED  NODE_LEFT
// logs-2024.01   0     r      UNASSIGNED  NODE_LEFT
// logs-2024.01   2     r      UNASSIGNED  NODE_LEFT
// ...

Tüm unassigned shard'lar replica ve sebep NODE_LEFT. Bir node düşmüş.

Adım 4: Node Durumu

GET _cat/nodes?v&h=name,ip,role,heap.percent,cpu,disk.used_percent,master

// Çıktı: 2 data node görünüyor, normalde 3 olmalı
// data-3 listede yok!

Adım 5: Allocation Explain

GET _cluster/allocation/explain

// Sonuç:
{
  "index": "orders-2024.01",
  "shard": 1,
  "primary": false,
  "can_allocate": "no",
  "allocate_explanation": "cannot allocate because allocation is not permitted to any of the nodes",
  "node_allocation_decisions": [
    {
      "node_name": "data-1",
      "node_decision": "no",
      "deciders": [
        {
          "decider": "same_shard",
          "decision": "NO",
          "explanation": "a copy of this shard is already allocated to this node [[orders-2024.01][1], node[data-1], primary]"
        }
      ]
    },
    {
      "node_name": "data-2",
      "node_decision": "no",
      "deciders": [
        {
          "decider": "same_shard",
          "decision": "NO",
          "explanation": "a copy of this shard is already allocated to this node"
        }
      ]
    }
  ]
}

Sorun net: 3 shard'lı index, replica=1 ama sadece 2 node var. Bazı shard'ların hem primary'si hem replica'sı aynı node'da olamayacağı için replica atanamıyor.

Adım 6: Çözüm

# Seçenek 1: Düşen node'u geri getir (en iyi)
# data-3'ü restart et

# Seçenek 2: Yeni node ekle
# Yeni data node kurulumu

# Seçenek 3 (geçici): Replica sayısını düşür
// Geçici çözüm — replica'yı düşür
PUT orders-2024.01/_settings
{
  "index.number_of_replicas": 0
}
// ⚠️ Bu, node düşerse veri kaybı riski demek!

Java ile Otomatik Health Checker

public class ClusterHealthChecker {
    private final ElasticsearchClient client;

    public ClusterHealthChecker(ElasticsearchClient client) {
        this.client = client;
    }

    public void diagnose() throws Exception {
        // 1. Cluster health
        var health = client.cluster().health();
        System.out.println("Status: " + health.status());
        System.out.println("Unassigned: " + health.unassignedShards());

        if (health.unassignedShards() == 0) {
            System.out.println("✅ All shards assigned!");
            return;
        }

        // 2. Unassigned shard'ları listele
        var shards = client.cat().shards(s -> s
            .headers("index,shard,prirep,state,unassigned.reason,node")
        );

        System.out.println("\n=== Unassigned Shards ===");
        for (var shard : shards.valueBody()) {
            if ("UNASSIGNED".equals(shard.state())) {
                System.out.printf("  %s [%s] %s — Reason: %s%n",
                    shard.index(), shard.shard(),
                    shard.prirep(), shard.unassignedReason());
            }
        }

        // 3. Allocation explain
        var explain = client.cluster().allocationExplain(e -> e);
        System.out.println("\n=== Allocation Explain ===");
        System.out.println("Index: " + explain.index());
        System.out.println("Shard: " + explain.shard());
        System.out.println("Primary: " + explain.primary());
        System.out.println("Can allocate: " + explain.canAllocate());
        System.out.println("Explanation: " + explain.allocateExplanation());
    }
}

10. Best Practices

✅ Yap

KonuÖneri
Allocation awarenessZone bazlı awareness kullan
Delayed allocationNode restart için 5-10 dakika bekle
Disk watermarkLow=%80, High=%85 — varsayılanlardan önce aksiyon al
Health monitoringHer dakika kontrol, alert kur
Allocation explainSorunu anlamadan çözmeye çalışma
Reroute retry_failedBaşarısız atamaları periyodik retry yap

❌ Yapma

KonuNeden
Yellow'u ignore etmeBir node daha düşerse kırmızı
accept_data_loss ile allocationSon çare — önce snapshot dene
Allocation disable unutmaMaintenance sonrası enable: all yapmazsan shard atanmaz
Flood stage'de watermark yükseltmeGeçici çözüm, asıl çözüm disk temizleme

11. Yaygın Hatalar ve Çözümleri

Hata 1: "Cluster RED ama veri var mı?"

# Adım 1: Red index'leri bul
GET _cat/indices?v&health=red

# Adım 2: Hangi primary shard kayıp?
GET _cat/shards?v&h=index,shard,prirep,state&s=state

# Adım 3: Node geri dönebilir mi?
# Evet → node'u restart et
# Hayır → snapshot'tan restore et
# Son çare → allocate_stale_primary (veri kaybı riski)

Hata 2: "Shard allocation timed out"

// Sorun: Recovery çok yavaş, timeout
// Çözüm: Recovery throttle'ı artır
PUT _cluster/settings
{
  "transient": {
    "indices.recovery.max_bytes_per_sec": "200mb",
    "cluster.routing.allocation.node_concurrent_incoming_recoveries": 4
  }
}

Hata 3: "Index read-only (flood stage)"

// Sorun: Disk flood stage'e ulaşmış, index read-only
// Adım 1: Disk aç (eski index sil, temp dosya temizle)
DELETE old-unnecessary-index-*

// Adım 2: Read-only block'u kaldır
PUT _all/_settings
{
  "index.blocks.read_only_allow_delete": null
}

// Adım 3: Watermark'ları kontrol et
GET _cat/allocation?v

Hata 4: "Allocation keeps failing"

# Sorun: Shard atama sürekli başarısız (retry max'a ulaşmış)
# Kontrol:
GET _cluster/allocation/explain

# Genelde neden: Mapping uyumsuzluğu, corrupt shard, disk dolu
# Çözüm:
POST _cluster/reroute?retry_failed=true

# Hâlâ başarısızsa: index'i kapatıp açmayı dene
POST problematic-index/_close
POST problematic-index/_open

12. Recovery Monitoring

Bir node cluster'a katıldığında veya shard taşındığında recovery başlar:

# Aktif recovery'leri izle
GET _cat/recovery?v&active_only&h=index,shard,time,type,stage,files_percent,bytes_percent,source_node,target_node

// Çıktı:
// index        shard time  type stage    files_percent bytes_percent source_node target_node
// products     0     2.5m  peer translog 100%          87.3%         data-1      data-3
// logs-2024.01 2     5.1m  peer index    56.2%         42.1%         data-2      data-3

Recovery Stages

StageAçıklama
initRecovery başlatılıyor
indexSegment dosyaları kopyalanıyor
verify_indexKopyalanan segment'ler doğrulanıyor
translogTranslog replay ediliyor
finalizeRecovery tamamlanıyor
doneTamamlandı

Özet

  1. Cluster health üç renkle özetlenir — Green (herkes yerinde), Yellow (replica eksik), Red (primary kayıp). Yellow'u asla ignore etmeyin — bir node daha düşerse RED olur.

  2. `_cluster/allocation/explain` shard'ın neden atanamadığını detaylı gösterir — sorunu anlamadan çözmeye çalışmayın, önce explain çıktısını okuyun.

  3. Disk watermark'ları shard atamayı doğrudan etkiler — low (%85) yeni atama durdurur, high (%90) shard taşır, flood stage (%95) index'i read-only yapar.

  4. Allocation awareness ile primary ve replica'yı farklı zone'lara dağıtarak zone arızasına karşı koruma sağlayın.

  5. Delayed allocation node restart senaryolarında saatler sürecek gereksiz veri taşımayı önler — 5-10 dakika beklemek mantıklıdır.

  6. Manuel reroute son çaredir — allocate_stale_primary ve allocate_empty_primary veri kaybına yol açabilir. Önce snapshot'tan restore etmeyi deneyin.