Elasticsearch Shard ve Replica Yönetimi

Yıllar içinde onlarca Elasticsearch cluster’ı yönetmiş biri olarak şunu net söyleyebilirim: Shard ve replica kavramlarını gerçekten anlamadan bu sistemi “yönetiyorum” demek biraz abartılı kalıyor. Çoğu ekip Elasticsearch’ü kuruyor, logları akıtıyor, Kibana’da güzel dashboard’lar yapıyor ve her şey yolundaymış gibi devam ediyor. Ta ki cluster sarı ya da kırmızıya dönene kadar. İşte o noktada shard yönetimini aceleyle öğrenmek zorunda kalıyorsunuz. Bu yazıda o aceleyi yaşamamanız için işin altını üstünü anlatacağım.

Shard Nedir, Neden Bu Kadar Önemlidir?

Elasticsearch, her index’i parçalara bölerek saklar. Bu parçalara shard denir. Bir index oluşturduğunuzda Elasticsearch arka planda o veriyi birden fazla parçaya bölüp farklı node’lara dağıtır. Bu mimari hem yatay ölçeklendirmeyi hem de paralel sorgu işlemeyi mümkün kılar.

Primary shard asıl veriyi tutar. Replica shard ise bu verinin kopyasıdır. Replica’ların iki temel amacı vardır: yüksek erişilebilirlik (bir node çökerse veri kaybolmaz) ve okuma performansı (sorgular primary ve replica’lara dağıtılabilir).

Peki neden herkes bu kadar çok shard açıyor ve sonradan pişman oluyor? Çünkü Elasticsearch dokümantasyonunun eski sürümlerinde varsayılan değer 5 primary shard’dı. Büyük bir cluster kuracaksanız bu makul görünebilir ama 50 tane küçük index için her birinde 5 shard açmak ciddi bir overhead yaratır. Her shard aslında bir Lucene instance’ıdır ve JVM heap’inden pay alır. 1000 shard’lık bir cluster’da bu rakam fark edilir düzeyde sistem kaynağı tüketimine dönüşür.

Shard Sayısını Doğru Belirlemek

Şu sıkça duyulan sorudan başlayalım: “Kaç shard açmalıyım?” Cevap her zaman “duruma göre” olmuştur ama biraz daha somutlaştıralım.

Elasticsearch ekibinin önerdiği yaklaşım şudur: Her shard yaklaşık 10-50 GB veri tutmalı. Bir index’inizin 200 GB veri tutacağını tahmin ediyorsanız 5-10 shard makul bir başlangıç noktasıdır. Ancak bu sadece depolama boyutu değil, aynı zamanda sorgu yükü ve index hızıyla da ilgilidir.

Pratik olarak şunu yapın: Önce küçük başlayın, büyüdükçe reindex edin ya da index template’lerini güncelleyin. Elasticsearch 7.0’dan itibaren varsayılan primary shard sayısı 1’e indirildi, bu doğru bir karar.

Mevcut cluster’ınızdaki shard dağılımına bakmak için:

curl -s -X GET "localhost:9200/_cat/shards?v&h=index,shard,prirep,state,docs,store,node" | sort -k1

Bu komut hangi shard’ın hangi node’da olduğunu, kaç döküman tuttuğunu ve ne kadar yer kapladığını gösterir. Çıktıyı gördüğünüzde bazı index’lerde dengesiz dağılım fark edebilirsiniz, bunu birazdan ele alacağız.

Belirli bir index için shard detaylarına inmek istiyorsanız:

curl -s -X GET "localhost:9200/_cat/shards/logstash-2024-*?v&pretty"

Index Template ile Varsayılan Shard Ayarları

Her index’i elle oluşturmak yerine template kullanmak en sağlıklı yaklaşım. Özellikle Logstash veya Filebeat ile gelen log verilerinde index adları tarih bazlı otomatik oluşturulduğu için template şart.

curl -X PUT "localhost:9200/_index_template/logs_template" 
  -H 'Content-Type: application/json' 
  -d '{
    "index_patterns": ["logs-*", "logstash-*"],
    "template": {
      "settings": {
        "number_of_shards": 2,
        "number_of_replicas": 1,
        "refresh_interval": "30s",
        "index.routing.allocation.total_shards_per_node": 3
      }
    },
    "priority": 100
  }'

Buradaki total_shards_per_node parametresi çok işe yarayan ama çoğu zaman göz ardı edilen bir ayar. Tek bir node’un belirli sayıdan fazla shard barındırmasını engeller ve veriyi cluster genelinde dengeli dağıtmanıza yardım eder.

refresh_interval değerini de duruma göre ayarlamanızı öneririm. Gerçek zamanlı analiz yapıyorsanız 1s makul, ama gecikmeye tolerans gösterebileceğiniz batch log işlemlerinde 30s veya hatta 60s performansı ciddi ölçüde artırır.

Replica Yönetimi: Sadece Yedek Değil

Replica’ları “yedek olsun” diye açıp geçmeyin. Replica yönetimi biraz daha nüanslıdır.

Okuma yükünü dağıtmak için replica’lar gerçekten değer üretir. Bir query geldiğinde Elasticsearch primary veya replica’ya yönlendirebilir, bu da throughput kapasitesini artırır. Ancak yazma yükü primary’ye gelir, primary başarıyla yazınca replica’lar güncellenir. Yani çok replica açmak yazma performansını olumsuz etkiler.

Mevcut bir index’in replica sayısını değiştirmek için:

curl -X PUT "localhost:9200/logstash-2024.01.15/_settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "index": {
      "number_of_replicas": 2
    }
  }'

Tek node’lu bir geliştirme ortamı kuruyorsanız replica sayısını 0 yapın. Aksi halde cluster “yellow” durumda kalır çünkü replica’yı barındıracak başka node yoktur. Bu durum production’da alarm vermelidir ama dev ortamında gereksiz gürültü yaratır.

curl -X PUT "localhost:9200/*/_settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "index": {
      "number_of_replicas": 0
    }
  }'

Cluster Sağlığını Anlamak ve Sorun Gidermek

Sabah geldiniz, Kibana açılmıyor, cluster red. Panik yapmadan önce şunlara bakın:

curl -s -X GET "localhost:9200/_cluster/health?pretty"

Çıktıda status alanına bakın:

  • green: Her şey yolunda, tüm primary ve replica shard’lar atanmış
  • yellow: Tüm primary’ler atanmış ama bazı replica’lar atanamamış (genellikle node eksikliği)
  • red: Bazı primary shard’lar atanamamış, veri kaybı riski var

Red durumda hangi index ve shard’ların sorunlu olduğunu görmek için:

curl -s -X GET "localhost:9200/_cluster/allocation/explain?pretty" 
  -H 'Content-Type: application/json' 
  -d '{
    "index": "logstash-2024.01.15",
    "shard": 0,
    "primary": true
  }'

Bu endpoint altın değerinde. Neden shard atanamıyor sorusunu Türkçe gibi açıklıyor size: disk doldu mu, node uyumsuz mu, retry limiti mi aşıldı?

Genel olarak atanamamış tüm shard’ların nedenini görmek için:

curl -s -X GET "localhost:9200/_cluster/allocation/explain?pretty"

Shard Rebalancing ve Manuel Taşıma

Cluster’a yeni bir node eklediniz ama shard’lar otomatik olarak eşit dağılmadı. Ya da bir node’u bakıma almadan önce tüm shard’larını başka node’lara taşımak istiyorsunuz. İşte burada reroute API devreye giriyor.

Shard rebalancing’i etkinleştirmek veya devre dışı bırakmak:

# Rebalancing'i devre dışı bırak (bakım öncesi)
curl -X PUT "localhost:9200/_cluster/settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "persistent": {
      "cluster.routing.rebalance.enable": "none"
    }
  }'

# Bakım sonrası tekrar etkinleştir
curl -X PUT "localhost:9200/_cluster/settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "persistent": {
      "cluster.routing.rebalance.enable": "all"
    }
  }'

Belirli bir shard’ı manuel olarak başka bir node’a taşımak:

curl -X POST "localhost:9200/_cluster/reroute" 
  -H 'Content-Type: application/json' 
  -d '{
    "commands": [
      {
        "move": {
          "index": "logstash-2024.01.15",
          "shard": 0,
          "from_node": "node-1",
          "to_node": "node-3"
        }
      }
    ]
  }'

Node isimlerini öğrenmek için:

curl -s -X GET "localhost:9200/_cat/nodes?v&h=name,ip,heapPercent,ramPercent,cpu,load_1m,diskUsedPercent"

Bu çıktı aynı zamanda node başlığında performans sorunlarını görmenizi sağlar. Heap yüzde 85’i geçmişse JVM garbage collection sorunları yaşıyor olabilirsiniz.

Disk Temizliği: ILM ile Eski Index Yönetimi

ELK stack ile log yönetimi yapıyorsanız ve disk yönetimini otomatize etmediyseniz er ya da geç “disk full” alarmıyla uyandırılırsınız. Index Lifecycle Management (ILM) bu sorunu çözmek için tasarlanmış.

Basit bir ILM policy’si: 30 günden eski loglar silinsin.

curl -X PUT "localhost:9200/_ilm/policy/logs_policy" 
  -H 'Content-Type: application/json' 
  -d '{
    "policy": {
      "phases": {
        "hot": {
          "min_age": "0ms",
          "actions": {
            "rollover": {
              "max_age": "1d",
              "max_size": "50gb"
            }
          }
        },
        "warm": {
          "min_age": "7d",
          "actions": {
            "shrink": {
              "number_of_shards": 1
            },
            "forcemerge": {
              "max_num_segments": 1
            }
          }
        },
        "delete": {
          "min_age": "30d",
          "actions": {
            "delete": {}
          }
        }
      }
    }
  }'

Buradaki shrink aksiyonu özellikle önemli. Warm aşamasına geçen, artık yazılmayan eski index’ler çok shard’a gerek duymaz. Shrink ile shard sayısını düşürüp kaynak tasarrufu yapabilirsiniz. Forcemerge ise Lucene segment’lerini birleştirerek okuma performansını artırır ve disk kullanımını azaltır.

Gerçek Dünya Senaryosu: Cluster Sarıya Döndüğünde

Geçen yıl bir müşterinin sisteminde tam gece yarısı Elasticsearch cluster’ı yellow’a döndü. Alertmanager bizi uyandırdığında duruma baktık: bir data node restart olmuş, o node üzerindeki shard’ların replica’ları başka node’lara atanmaya çalışılıyor ama atanamazdı çünkü cluster.routing.allocation.same_shard.host ayarı aktifti ve tüm node’lar aynı fiziksel sunucunun farklı VM’lerindeydi.

Dersi şu oldu: Infrastructure tasarımı Elasticsearch konfigürasyonunuzu doğrudan etkiler. Replica’larınızın gerçekten farklı fiziksel donanımda olmasını istiyorsanız allocation awareness kullanın:

curl -X PUT "localhost:9200/_cluster/settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "persistent": {
      "cluster.routing.allocation.awareness.attributes": "rack_id"
    }
  }'

Node başlatılırken de ilgili attribute’u tanımlayın:

# elasticsearch.yml içinde
node.attr.rack_id: rack1

Bu sayede primary ve replica’ların farklı rack’lerde (veya farklı availability zone’larda) olmasını garantileyebilirsiniz.

Shard Boyutunu İzlemek ve Aşırı Büyüyen Shard’larla Baş Etmek

Zaman içinde bazı shard’lar beklenenden çok büyüyebilir. Özellikle rollover kullanmıyorsanız ve index tarih bazlı oluşturulmuyorsa tek bir index onlarca GB’a ulaşabilir. Bu hem query performansını hem de recovery süresini olumsuz etkiler.

En büyük shard’ları listelemek:

curl -s -X GET "localhost:9200/_cat/shards?v&h=index,shard,store,node&s=store:desc" | head -20

Eğer bir index aşırı büyümüşse ve onu küçük parçalara bölmek istiyorsanız split API’ını kullanabilirsiniz:

# Önce index'i read-only yap
curl -X PUT "localhost:9200/buyuk-index/_settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "settings": {
      "index.blocks.write": true
    }
  }'

# Sonra split et
curl -X POST "localhost:9200/buyuk-index/_split/buyuk-index-v2" 
  -H 'Content-Type: application/json' 
  -d '{
    "settings": {
      "index.number_of_shards": 4
    }
  }'

Split sonrası eski index’i silebilir ya da bir süre daha tutabilirsiniz. Split işlemi hard link kullandığı için nispeten hızlı tamamlanır, veriyi kopyalamaz.

Performans İyileştirme: Shard’larla İlgili Dikkat Edilmesi Gerekenler

Bir cluster’ın shard yönetimi açısından sağlıklı olup olmadığını anlamak için düzenli olarak şu metriklere bakın:

  • Toplam shard sayısı: Node başına 20-25 shard genellikle makul bir üst sınır. Bunu aşmaya başladığınızda JVM heap baskısı artar.
  • Shard boyutları: 50 GB üzeri shard’lar recovery süresini uzatır. Rollover ile bunu kontrol altında tutun.
  • Unassigned shard sayısı: Her zaman 0 olmalı production’da.
  • Relocating shard sayısı: Çok uzun süre relocating durumunda kalıyorsa throttle ayarlarını gözden geçirin.

Recovery hızını artırmak için throttle ayarlarını geçici olarak yükseltebilirsiniz (ama dikkatli olun, ağ ve disk I/O’yu etkiler):

curl -X PUT "localhost:9200/_cluster/settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "transient": {
      "indices.recovery.max_bytes_per_sec": "500mb"
    }
  }'

Normal koşullarda bu değer 40mb’dır. Bakım penceresinde geçici olarak artırmak mantıklıdır.

Sonuç

Elasticsearch shard ve replica yönetimi, öğrenilmesi gereken ama çoğu zaman acil bir sorun çıkana kadar ertelenen bir konudur. Oysa doğru yapılandırılmış bir cluster hem performans hem de dayanıklılık açısından ciddi fark yaratır.

Özetlemek gerekirse: Shard sayısını gerçekçi veri boyutunuza göre belirleyin ve şişirmeyin. Replica’ları sadece yedek olarak değil, okuma kapasitesi olarak da değerlendirin. ILM ile disk yönetimini otomatize edin, yoksa gece yarısı alarmıyla uğraşırsınız. Allocation awareness ile replica’larınızın gerçekten farklı donanımlarda olduğundan emin olun. Ve _cluster/allocation/explain API’ını ezbere bilin, her sorunun cevabı orada gizlidir.

Bu konuları içselleştirdikten sonra Elasticsearch’ün “kendiliğinden çalışan sihirli bir kutu” değil, dikkatli bir yönetim gerektiren güçlü bir sistem olduğunu anlayacaksınız. Ve o anlayışla birlikte cluster’larınız çok daha kararlı çalışmaya başlayacak.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir