← Kursa Dön
📄 Text · 35 min

Shards ve Replicas — Dağıtık Mimari

Dağıtık Mimari Temelleri

Bir pizza düşün. Tek başına koca bir pizza yiyemezsin — dilimlere ayırırsın. Her dilimi farklı bir tabağa koyabilirsin. Arkadaşların da yardım edebilir — her biri bir dilimi alır, paralel olarak yersiniz. İşte shard, Elasticsearch'teki pizza dilimi. Veriyi parçalara ayırarak birden fazla makineye yayar ve paralel işleme sağlar.

Peki ya bir dilim yere düşerse? İşte replica bu durumda devreye girer — her dilimin bir kopyası başka bir tabakta duruyor. Orijinal kaybolursa kopya orada.

Bu ders, Elasticsearch'ün dağıtık doğasını anlaman için kritik. Production'da doğru shard stratejisi belirlemek, performans ve maliyeti doğrudan etkiler.


Shard Nedir?

Shard, bir index'in fiziksel parçasıdır. Her shard kendi başına çalışabilen bir Lucene instance'ıdır. Lucene, tüm arama işlemlerini gerçekleştiren alt motordur — Elasticsearch onu orkestra eder.

Index: "products" (tüm ürün verileri — 10.000 doküman)
├── Shard 0 (Doküman 1-3333)      → Node 1'de
├── Shard 1 (Doküman 3334-6666)   → Node 2'de
└── Shard 2 (Doküman 6667-10000)  → Node 3'te

Bir index oluşturduğunda shard sayısını belirtirsin:

PUT /products
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}

Neden Shard'lara Bölüyoruz?

1. Paralel İşleme (Concurrency)

3 shard'lı bir index'e arama sorgusu gönderdiğinde, 3 shard aynı anda paralel çalışır. Tek shard'da 300ms sürecek sorgu, 3 shard'da ~100ms sürer.

2. Yatay Ölçekleme (Horizontal Scaling)

Tek makinenin diski 500GB. 1TB verin varsa ne yaparsın? 2 makineye yayarsın. 5TB olursa 10 makineye. Shard'lar bunu mümkün kılar.

3. Veri Dağıtımı (Distribution)

Shard'lar cluster'daki node'lara otomatik dağıtılır. Yeni node eklediğinde Elasticsearch shard'ları otomatik yeniden dengeler (rebalance).

Primary Shard ve Replica Shard

İki tür shard var:

Primary Shard: Orijinal veri parçası. Yazma işlemleri (index, update, delete) önce primary shard'a gider.

Replica Shard: Primary shard'ın birebir kopyası. İki amaca hizmet eder:

  1. Yüksek erişilebilirlik (HA): Primary çökerse replica devralır

  2. Okuma performansı: Arama sorguları replica'lardan da cevaplanabilir

Index: "products" (3 primary, 1 replica)

Node 1:  [P0] [R1] [R2]
Node 2:  [R0] [P1] [R2']
Node 3:  [R0'] [R1'] [P2]

P = Primary Shard
R = Replica Shard

⚠️ Kritik Kural: Primary shard ile onun replica'sı asla aynı node'da bulunmaz. Çünkü node çökerse ikisi de kaybolurdu — replica'nın tüm amacı boşa giderdi.

Toplam Shard Sayısı Hesabı

Toplam shard = primary_shards × (1 + number_of_replicas)

Örnek: 3 primary, 1 replica
Toplam = 3 × (1 + 1) = 6 shard

Örnek: 5 primary, 2 replica
Toplam = 5 × (1 + 2) = 15 shard

Shard Dağılımını Görme

// Tüm shard'ları listele
GET /_cat/shards?v

// Belirli bir index'in shard'ları
GET /_cat/shards/products?v

// Yanıt:
// index    shard prirep state      docs  store node
// products 0     p      STARTED    3333  15mb  node-1
// products 0     r      STARTED    3333  15mb  node-2
// products 1     p      STARTED    3333  15mb  node-2
// products 1     r      STARTED    3333  15mb  node-3
// products 2     p      STARTED    3334  15mb  node-3
// products 2     r      STARTED    3334  15mb  node-1

// prirep: p = primary, r = replica
// state: STARTED = aktif, UNASSIGNED = atanamamış, RELOCATING = taşınıyor

// Shard allocation açıklaması (sorun varsa)
GET /_cluster/allocation/explain

// Her node'daki shard dağılımı
GET /_cat/allocation?v

Shard Sayısını Belirlemek

Bu Elasticsearch'teki en kritik tasarım kararlarından biri. Yanlış shard sayısı ya performans sorunlarına ya da gereksiz kaynak israfına yol açar.

Shard Başına Önerilen Boyut

Elastic'in resmi önerisi:

Her shard: 10GB ile 50GB arası
Hedef: ~30GB per shard (ideal nokta)
Minimum: 1GB'dan küçük shard'lardan kaçın
Toplam VeriÖnerilen Primary ShardMantık
1 GB1 shardGereksiz overhead'den kaçın
10 GB1 shardHâlâ tek shard yeterli
50 GB2 shard~25GB per shard
100 GB3-5 shard~20-33GB per shard
500 GB10-20 shard~25-50GB per shard
1 TB20-40 shard~25-50GB per shard
10 TB200-400 shardGenelde çoklu index ile dağıtılır

Çok Az Shard — Sorunlar

Index: "big-data" (1 shard, 500GB)
└── Shard 0 (500GB) → Tek node'da

Sorunlar:
❌ Paralel işleme yok — tüm sorgular tek shard'a gider
❌ Node'un diski dolabilir — ölçekleyemezsin
❌ Recovery çok uzun sürer — node çökerse 500GB kopyalanması gerekir
❌ Rebalance yapılamaz — veriyi bölemezsin
❌ Hot spot — tek node aşırı yüklenir

Çok Fazla Shard — Sorunlar

Index: "small-data" (100 shard, 100MB toplam)
├── Shard 0  (1MB)
├── Shard 1  (1MB)
├── ...
└── Shard 99 (1MB)

Sorunlar:
❌ Her shard ~50MB memory overhead (Lucene segments, file handles, buffers)
❌ 100 shard × 50MB = 5GB sadece overhead — verin sadece 100MB!
❌ Koordinasyon maliyeti — her sorgu 100 shard'a fan-out yapar
❌ Master node'da cluster state şişmesi
❌ Merge overhead — her shard'da ayrı segment yönetimi

Shard Sayısı Hesaplama Formülü

Primary shard sayısı = Toplam veri boyutu / Hedef shard boyutu

Örnek:
- Beklenen veri: 150 GB
- Hedef shard boyutu: 30 GB
- Primary shard sayısı: 150 / 30 = 5

Toplam shard (replica dahil):
5 primary × (1 + 1 replica) = 10 shard
Minimum node sayısı: 2 (replica kuralı gereği)

Bir Diğer Kural: Node Başına Shard

Genel kural: Node başına 20 shard per GB heap

Örnek:
- Heap: 4GB
- Maksimum shard/node: 4 × 20 = 80 shard
- Ama genellikle node başına 200-400 shard üst sınır önerilir

Zaman Bazlı Index'lerde Shard Stratejisi

Log verisi gibi sürekli büyüyen veriler için:

// Günlük index — her gün yeni index oluşur
// app-logs-2025.01.15 → 1 shard (günlük ~5GB veri)
// app-logs-2025.01.16 → 1 shard
// app-logs-2025.01.17 → 1 shard
// ...

PUT /_index_template/logs-template
{
  "index_patterns": ["app-logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    }
  }
}

// 1 yıllık veri = 365 index × 1 primary × 2 (1 replica) = 730 shard
// Bu yönetilebilir bir sayı

Zaman bazlı index'lerde her index küçük olduğu için shard sayısı az tutulur. Ölçekleme, index sayısıyla sağlanır. Eski veriyi silmek de kolay — sadece eski index'i sil.


Replica Detaylı

Replica, primary shard'ın birebir kopyasıdır. Ama basit bir kopyadan çok daha fazlası.

Replica'nın İki Temel Görevi

1. Yüksek Erişilebilirlik (High Availability)

Bir node çöktüğünde veri kaybı olmaz:

Senaryo: Node 2 çöktü

ÖNCE:
Node 1: [P0] [R1]
Node 2: [P1] [R0]  ← ÇÖKTÜ!
Node 3: [P2] [R1']

SONRA (otomatik recovery):
1. Elasticsearch R0'ı bulur (Node 1 veya Node 3'te olabilir)
2. R0, P1'e promote edilir (primary olur)
3. Yeni replica'lar oluşturulur (kalan node'lara dağıtılır)

Node 1: [P0] [R1] [P1*]   ← R0 artık yeni P1
Node 3: [P2] [R1'] [R0*]  ← Yeni R0 oluşturuldu

Veri kaybı: SIFIR ✅
Servis kesintisi: Birkaç saniye (shard relocation süresi)

2. Okuma Performansı

Arama sorguları hem primary hem replica shard'lardan cevaplanabilir:

1 primary + 1 replica = 2× okuma kapasitesi
1 primary + 2 replica = 3× okuma kapasitesi

Arama sorgusu geldi → Koordinator node seçer:
  Shard 0 → Node 1 (primary) VEYA Node 2 (replica) — en az meşgul olanı
  Shard 1 → Node 2 (primary) VEYA Node 3 (replica) — en az meşgul olanı
  Shard 2 → Node 3 (primary) VEYA Node 1 (replica) — en az meşgul olanı

Elasticsearch, Adaptive Replica Selection ile en hızlı yanıt verecek shard'ı seçer.

Yazma İşleminde Replica'nın Rolü

Client: "Bu dokümanı index'le"
                ↓
1. Koordinator → Routing → Primary Shard (Node 2)
2. Primary Shard yazar → Başarılı
3. Primary → Tüm replica'lara paralel gönderir
4. Replica'lar yazar → Başarılı
5. Primary → Client'a "201 Created" döner

wait_for_active_shards parametresi bu davranışı kontrol eder:
- "all": Tüm replica'lar yazana kadar bekle (en güvenli, en yavaş)
- "1": Sadece primary yazınca dön (hızlı ama veri kaybı riski)
- varsayılan: "1" (sadece primary)
// Tüm replica'ların yazmasını bekle
PUT /products/_doc/1?wait_for_active_shards=all
{
  "name": "Laptop",
  "price": 15000
}

// Minimum 2 shard'ın aktif olmasını bekle
PUT /products/_doc/2?wait_for_active_shards=2
{
  "name": "Mouse",
  "price": 300
}

Replica Ayarları

// Index oluşturulurken
PUT /products
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1    // Her primary'nin 1 kopyası
  }
}

// Replica sayısı sonradan değiştirilebilir!
PUT /products/_settings
{
  "number_of_replicas": 2    // Artık her primary'nin 2 kopyası var
}

// Replica'yı kapat (development ortamı veya yazma performansı için)
PUT /products/_settings
{
  "number_of_replicas": 0
}

💡 İpucu: Primary shard sayısı index oluşturulduktan sonra değiştirilemez (split/shrink API hariç). Replica sayısı ise istediğin zaman değiştirilebilir. Bu fark çok önemli.

Cluster Durumu ve Replica İlişkisi

GET /_cluster/health

// Yanıt:
{
  "status": "green",           // veya "yellow" veya "red"
  "number_of_nodes": 3,
  "active_primary_shards": 3,
  "active_shards": 6,
  "unassigned_shards": 0
}
StatusAnlamNe Yapmalı?
🟢 greenTüm primary + replica atanmışHer şey yolunda
🟡 yellowTüm primary atanmış, bazı replica atanamadıReplica sorunu — ama veri erişilebilir
🔴 redBazı primary shard'lar atanamadıACİL — veri erişilemez olabilir

Tek node cluster neden "yellow"?

Ayar: 1 primary, 1 replica
Node sayısı: 1

Primary shard → Node 1'e atandı ✅
Replica shard → Nereye atanacak? Node 1'e atanamaz (aynı node kuralı) → ATANAMADI ⚠️

Sonuç: Cluster status = YELLOW

Tek node'da çalışıyorsan replica'yı 0 yap:

PUT /my-index/_settings
{
  "number_of_replicas": 0
}
// Artık cluster status = GREEN ✅

Routing — Document Hangi Shard'a Gider?

Bir document index'lendiğinde hangi shard'a yazılacağı routing formülü ile belirlenir:

shard_number = hash(_routing) % number_of_primary_shards

Varsayılan _routing değeri document'ın _id'sidir:

Document ID: "abc123"
hash("abc123") = 587234891
587234891 % 3 = 1

→ Bu document Shard 1'e yazılır

Bu formül deterministik — aynı ID her zaman aynı shard'a gider. Bu yüzden GET /products/_doc/abc123 dediğinde Elasticsearch hangi shard'a bakacağını bilir — tüm shard'ları taramaz.

Custom Routing

Belirli bir kritere göre ilişkili document'ları aynı shard'a yönlendirebilirsin:

// Aynı müşterinin tüm siparişleri aynı shard'da
PUT /orders/_doc/order-1?routing=customer-42
{
  "customer_id": "customer-42",
  "product": "Laptop",
  "amount": 75000
}

PUT /orders/_doc/order-2?routing=customer-42
{
  "customer_id": "customer-42",
  "product": "Mouse",
  "amount": 300
}

// Arama yaparken de routing belirt — sadece 1 shard taranır
GET /orders/_search?routing=customer-42
{
  "query": {
    "term": { "customer_id": "customer-42" }
  }
}
// 100 shard yerine 1 shard tarandi → ~100x daha hızlı!

⚠️ Dikkat: Custom routing ile bazı shard'lar diğerlerinden çok daha fazla veri barındırabilir (hot shard / data skew). Routing key'i dengeli dağılımlı olmalı.

Neden Primary Shard Sayısı Değiştirilemez?

Routing formülünü hatırla:

shard = hash(id) % number_of_primary_shards

Shard sayısı 3'ten 5'e değişirse:

hash("abc123") % 3 = 1  (Shard 1'deydi)
hash("abc123") % 5 = 3  (Artık Shard 3'e bakıyor — ama veri Shard 1'de!)
→ Document bulunamaz!

Bu yüzden shard sayısı değiştiğinde tüm verinin yeniden dağıtılması gerekir — yani reindex.


Arama İşleminin Shard'larla Çalışması

Bir arama sorgusunun perde arkasında ne olduğunu adım adım görelim:

Phase 1: Query (Sorgu Fazı)

Client → GET /products/_search { "query": { "match": { "name": "laptop" } }, "size": 10 }

1. Client → Koordinator Node'a sorgu gönderir
2. Koordinator, sorguyu TÜM ilgili shard'lara (primary veya replica) yönlendirir
   - Shard 0 (Node 1) → Local arama başlat
   - Shard 1 (Node 2) → Local arama başlat
   - Shard 2 (Node 3) → Local arama başlat
3. Her shard kendi local top-10 sonucunu döndürür (sadece _id ve _score)
4. Koordinator, 3 × 10 = 30 sonucu birleştirir, global top-10'u belirler

Phase 2: Fetch (Getirme Fazı)

5. Koordinator, seçilen 10 document'ın _source verisini ilgili shard'lardan ister
   - Shard 0'dan 3 doküman
   - Shard 1'den 4 doküman
   - Shard 2'den 3 doküman
6. Shard'lar _source verilerini gönderir
7. Koordinator, nihai sonucu sıralı şekilde client'a döndürür
// Bu sorgu:
GET /products/_search
{
  "query": { "match": { "name": "laptop" } },
  "size": 10,
  "from": 0
}

// Aslında her shard'da "from + size" kadar sonuç hesaplanır:
// Her shard → top (0 + 10) = 10 sonuç döner
// Koordinator → 30 sonucu birleştirir → en iyi 10'u seçer

// Deep pagination sorunu:
GET /products/_search
{
  "query": { "match_all": {} },
  "size": 10,
  "from": 10000
}
// Her shard → top 10010 sonuç hesaplar!
// Koordinator → 30030 sonucu birleştirir!
// Bu yüzden from + size > 10000 performans sorunları yaratır.
// Çözüm: search_after veya scroll API (Bölüm 6'da)

Node Tipleri ve Shard İlişkisi

┌──────────────────────────────────────────────────────────────┐
│                       CLUSTER                                 │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │ Master Node  │  │  Data Node 1 │  │  Data Node 2 │      │
│  │  (Yönetici)  │  │   (İşçi)     │  │   (İşçi)     │      │
│  │              │  │ [P0][R1][R2] │  │ [R0][P1][P2] │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
│         ↕                 ↕                 ↕               │
│  Cluster state       Veri saklama      Veri saklama         │
│  Index yönetimi      Arama             Arama                │
│  Shard allocation    Indexleme          Indexleme            │
└──────────────────────────────────────────────────────────────┘
Node TipiRolShard Saklar mı?
MasterCluster yönetimi, shard allocation kararlarıGenelde hayır (dedicated master)
DataVeri saklama, arama, indexlemeEvet — asıl iş burada
CoordinatingSorguları yönlendirme, sonuç birleştirmeHayır
IngestVeri dönüşüm pipeline'larıHayır
MLMachine Learning işleriHayır

Küçük cluster'larda (2-3 node) her node tüm rolleri üstlenir. Büyük cluster'larda roller ayrılır — dedicated master, dedicated data node'lar.


Index Lifecycle Management (ILM) — Kısa Tanıtım

Zaman bazlı verilerde shard yönetimini otomatikleştirmek için ILM kullanılır:

// ILM Policy oluştur
PUT /_ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "30gb",
            "max_age": "7d"
          }
        }
      },
      "warm": {
        "min_age": "30d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          }
        }
      },
      "cold": {
        "min_age": "90d",
        "actions": {
          "readonly": {}
        }
      },
      "delete": {
        "min_age": "365d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

// Policy'yi index template'e bağla
PUT /_index_template/logs-template
{
  "index_patterns": ["app-logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs-policy"
    }
  }
}

Yaşam döngüsü:

Hot   (0-7 gün):    Yüksek performanslı SSD, aktif yazma, tam replica
Warm  (7-90 gün):   Okuma ağırlıklı, shrink + forcemerge ile optimize
Cold  (90-365 gün): Düşük kaynak, sadece nadir sorgular
Delete (365+ gün):  Otomatik silme — disk alanı geri kazanılır

Split ve Shrink API

Shard sayısını doğrudan değiştirmek mümkün değil ama bu API'lerle dolaylı olarak yapılabilir:

Shrink — Shard Sayısını Azalt

// 1. Tüm shard'ları tek node'a taşı ve readonly yap
PUT /products/_settings
{
  "settings": {
    "index.routing.allocation.require._name": "node-1",
    "index.blocks.write": true
  }
}

// 2. Shard sayısını azalt (bölünebilir olmalı: 6→3, 6→2, 6→1)
POST /products/_shrink/products-shrunk
{
  "settings": {
    "index.number_of_shards": 1,
    "index.number_of_replicas": 1,
    "index.routing.allocation.require._name": null,
    "index.blocks.write": null
  }
}

// 3. Alias'ı güncelle
POST /_aliases
{
  "actions": [
    { "remove": { "index": "products", "alias": "products-alias" } },
    { "add":    { "index": "products-shrunk", "alias": "products-alias" } }
  ]
}

Split — Shard Sayısını Artır

// 1. readonly yap
PUT /products/_settings
{
  "settings": {
    "index.blocks.write": true
  }
}

// 2. Shard sayısını artır (çarpanı olmalı: 1→2, 1→3, 2→4, 2→6)
POST /products/_split/products-split
{
  "settings": {
    "index.number_of_shards": 6,
    "index.blocks.write": null
  }
}

⚠️ Her iki operasyon da yeni bir index oluşturur. Bu yüzden alias kullanmak çok önemli.


Java ile Shard Bilgisi Sorgulama

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
import co.elastic.clients.elasticsearch.cat.ShardsResponse;
import co.elastic.clients.elasticsearch.cat.shards.ShardsRecord;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;

class Main {
    public static void main(String[] args) throws Exception {
        RestClient restClient = RestClient.builder(
            new HttpHost("localhost", 9200)
        ).build();
        ElasticsearchClient client = new ElasticsearchClient(
            new RestClientTransport(restClient, new JacksonJsonpMapper())
        );

        // Cluster health kontrolü
        HealthResponse health = client.cluster().health();
        System.out.println("Status: " + health.status());
        System.out.println("Nodes: " + health.numberOfNodes());
        System.out.println("Data nodes: " + health.numberOfDataNodes());
        System.out.println("Active primary shards: " + health.activePrimaryShards());
        System.out.println("Active shards (total): " + health.activeShards());
        System.out.println("Relocating shards: " + health.relocatingShards());
        System.out.println("Initializing shards: " + health.initializingShards());
        System.out.println("Unassigned shards: " + health.unassignedShards());

        // Shard listesi
        ShardsResponse shards = client.cat().shards();
        for (ShardsRecord record : shards.valueBody()) {
            System.out.printf("Index: %-15s | Shard: %s | Type: %s | State: %-10s | Docs: %s | Size: %s | Node: %s%n",
                record.index(), record.shard(), record.prirep(),
                record.state(), record.docs(), record.store(), record.node()
            );
        }

        // Index ayarlarını kontrol et (shard/replica sayısı)
        var settings = client.indices().getSettings(g -> g.index("products"));
        var indexSettings = settings.get("products").settings().index();
        System.out.println("Number of shards: " + indexSettings.numberOfShards());
        System.out.println("Number of replicas: " + indexSettings.numberOfReplicas());

        restClient.close();
    }
}

Gerçek Dünya Senaryosu: E-Ticaret Shard Planlaması

Bir e-ticaret platformu planlıyorsun:

Ürünler: 5 milyon ürün × ortalama 2KB = ~10GB
  → 1 primary shard yeterli
  → 1 replica (HA için)

Siparişler: Günlük 50.000 sipariş × 1KB = ~50MB/gün = ~18GB/yıl
  → Aylık index: orders-2025.01, orders-2025.02...
  → Her index 1 shard (aylık ~1.5GB)
  → 1 replica

Arama logları: Günlük 10 milyon arama × 500B = ~5GB/gün
  → Günlük index: search-logs-2025.01.15
  → Her index 1 shard (günlük ~5GB)
  → 0 replica (kaybedilse de önemli değil)
  → ILM: 30 gün sonra sil

Uygulama logları: Günlük 50 milyon log × 200B = ~10GB/gün
  → Günlük index
  → Her index 1 shard
  → 1 replica
  → ILM: 90 gün warm, 365 gün sonra sil
// E-ticaret ürün index'i
PUT /products
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  }
}

// Sipariş index template
PUT /_index_template/orders-template
{
  "index_patterns": ["orders-*"],
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    }
  }
}

// Arama log template
PUT /_index_template/search-logs-template
{
  "index_patterns": ["search-logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 0,
      "index.lifecycle.name": "search-logs-policy"
    }
  }
}

Best Practices

Shard başına 10-50GB hedefle — Çok küçük shard overhead yaratır, çok büyük shard esneklik kaybettirir

Tek node'da replica 0 yap — Yoksa cluster hep yellow kalır ve gereksiz uyarı üretir

Production'da minimum 3 node — High availability ve proper replica dağılımı için

Zaman bazlı veriler için daily/weekly/monthly index — Eski veriyi temizlemek kolay

ILM kullan — Hot-warm-cold-delete lifecycle'ı otomatikleştir

Shard sayısını veri boyutuna göre belirle — 1GB veri için 10 shard oluşturma

Cluster health'i izle — green kalmasını sağla, yellow ve red'i ciddiye al

Alias kullan — Shard değişikliği (shrink/split) gerektiğinde zero-downtime geçiş


Yaygın Hatalar

❌ "Her index'e 5 shard veriyorum"

Elasticsearch 6.x'in varsayılanı 5 shard idi. 7.x'te 1'e düşürüldü — çoğu index için 1 yeterli. Ama insanlar hâlâ eski alışkanlıkla 5 yazıyor.

❌ "Tek node'da replica 1 kullanıyorum"

Replica aynı node'a atanamaz. Tek node'da replica 0 yap.

❌ "Shard sayısını sonra ayarlarım"

Primary shard sayısı değiştirilemez. İlk günden doğru planlama yap. Split/Shrink API var ama overhead'li ve yeni index oluşturur.

❌ "Binlerce küçük index oluşturuyorum"

Her index en az 1 shard. 10.000 index × 1 shard × 1 replica = 20.000 shard. Bu master node'u ezer. Data streams veya index consolidation düşün.

❌ "Cluster red oldu, panik!"

Red status acil ama panik yapmak yerine sistematik debug:

// 1. Hangi index'ler red?
GET /_cat/indices?health=red&v

// 2. Hangi shard'lar atanamıyor?
GET /_cat/shards?h=index,shard,prirep,state,unassigned.reason&s=state:desc

// 3. Neden atanamıyor?
GET /_cluster/allocation/explain

Özet

  • Shard, index'in fiziksel parçasıdır — her shard bağımsız bir Lucene instance'ı

  • Primary shard orijinal veri, replica shard kopyasıdır — farklı node'larda bulunur

  • Primary shard sayısı index oluşturulurken belirlenir ve değiştirilemez (split/shrink hariç)

  • Replica sayısı istediğin zaman değiştirilebilir

  • Cluster durumu: green (tümü atanmış), yellow (replica eksik), red (primary eksik)

  • Shard başına 10-50GB hedefle — çok az veya çok fazla shard performansı bozar

  • Document routing formülü: hash(_id) % number_of_shards — bu yüzden shard sayısı sabit

  • Arama iki fazda çalışır: Query (her shard local top-N) + Fetch (seçilen sonuçların _source'ları)

  • ILM ile hot-warm-cold-delete lifecycle'ı otomatikleştir

Bir sonraki derste Inverted Index konusunu işleyeceğiz — Elasticsearch'ün milisaniyede milyonlarca kayıt arayabilmesinin sırrını öğreneceğiz!