← Kursa Dön
📄 Text · 30 min

Cross-Cluster Search ve Replication

Giriş — Multi-Cluster Yapılandırma

Bir şirketin İstanbul, Londra ve New York'ta ofisleri olduğunu düşün. Her ofiste kendi arşivi var. İstanbul'daki çalışan bir belge arıyorsa, sadece İstanbul arşivinde değil, gerektiğinde Londra ve New York arşivlerinde de arayabilmeli. Ama tüm belgeleri tek bir depoda toplamak yerine, her ofis kendi arşivini tutsun ve sorgu geldiğinde diğer ofislerin arşivlerini de tarasın — hem verimli hem de her lokasyon bağımsız çalışabilir.

Elasticsearch'te Cross-Cluster Search (CCS) tam bunu yapar: birden fazla cluster'ı tek bir sorgu ile arayabilirsiniz. Cross-Cluster Replication (CCR) ise bir cluster'daki veriyi otomatik olarak başka bir cluster'a kopyalar — disaster recovery ve coğrafi yakınlık için.


1. Neden Multi-Cluster?

Tek Cluster Yetmediği Durumlar

SenaryoÇözüm
Coğrafi dağılım (EU, US, APAC)Her bölgede local cluster, CCS ile birleştir
Disaster recoveryPrimary + DR cluster, CCR ile replikasyon
Organizasyonel izolasyonDepartman/takım bazlı cluster'lar
Versiyon bağımsızlığıFarklı cluster'lar farklı versiyonlarda olabilir
ComplianceVeri belirli bölgede kalmalı (GDPR)
Scaling sınırıTek cluster çok büyüdüyse bölme

Multi-Cluster vs Tek Büyük Cluster

ÖzellikTek ClusterMulti-Cluster
YönetimBasitKarmaşık
LatencyDüşük (aynı DC)Bölgeler arası yüksek
HANode seviyesindeCluster seviyesinde
ScalingSınırlıSınırsız
ComplianceZorKolay (bölgesel veri)

2. Cross-Cluster Search (CCS) — Uzaktan Arama

CCS Nasıl Çalışır?

  1. Local cluster, uzak cluster'a bağlantı kurar

  2. Sorgu hem local hem remote cluster'da çalışır

  3. Sonuçlar local cluster'da birleştirilir

  4. Client'a döner

Remote Cluster Bağlantısı Kurma

// Local cluster'da remote cluster tanımla
PUT _cluster/settings
{
  "persistent": {
    "cluster": {
      "remote": {
        "eu-cluster": {
          "seeds": ["eu-master-1:9300", "eu-master-2:9300", "eu-master-3:9300"],
          "transport.compress": true,
          "skip_unavailable": true
        },
        "us-cluster": {
          "seeds": ["us-master-1:9300", "us-master-2:9300"],
          "transport.compress": true,
          "skip_unavailable": true
        }
      }
    }
  }
}

Bağlantı Kontrolü

GET _remote/info

// Yanıt:
{
  "eu-cluster": {
    "connected": true,
    "mode": "sniff",
    "seeds": ["eu-master-1:9300", "eu-master-2:9300"],
    "num_nodes_connected": 5,
    "max_connections_per_cluster": 3,
    "initial_connect_timeout": "30s",
    "skip_unavailable": true
  },
  "us-cluster": {
    "connected": true,
    "mode": "sniff",
    "seeds": ["us-master-1:9300"],
    "num_nodes_connected": 3,
    "max_connections_per_cluster": 3,
    "initial_connect_timeout": "30s",
    "skip_unavailable": false
  }
}

CCS ile Arama

Remote cluster'ın index'ine <cluster-name>:<index-name> formatıyla erişilir:

// Sadece remote cluster'da ara
GET eu-cluster:logs-*/_search
{
  "query": {
    "bool": {
      "filter": [
        { "range": { "@timestamp": { "gte": "now-1h" } } },
        { "term": { "level": "ERROR" } }
      ]
    }
  },
  "size": 20
}

// Hem local hem remote cluster'da ara
GET logs-*,eu-cluster:logs-*,us-cluster:logs-*/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "connection timeout" } }
      ],
      "filter": [
        { "range": { "@timestamp": { "gte": "now-24h" } } }
      ]
    }
  },
  "size": 50,
  "sort": [
    { "@timestamp": "desc" }
  ]
}

CCS ile Aggregation

// Tüm cluster'lardaki hata dağılımı
GET logs-*,eu-cluster:logs-*,us-cluster:logs-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "range": { "@timestamp": { "gte": "now-24h" } } }
      ]
    }
  },
  "aggs": {
    "errors_by_service": {
      "terms": {
        "field": "service.keyword",
        "size": 20
      },
      "aggs": {
        "error_count": {
          "filter": {
            "term": { "level": "ERROR" }
          }
        }
      }
    },
    "errors_over_time": {
      "date_histogram": {
        "field": "@timestamp",
        "fixed_interval": "1h"
      },
      "aggs": {
        "error_rate": {
          "filter": {
            "term": { "level": "ERROR" }
          }
        }
      }
    }
  }
}

skip_unavailable Parametresi

// skip_unavailable: true → Remote cluster çökse bile local sonuçlar döner
// skip_unavailable: false → Remote cluster çökerse tüm sorgu hata verir

PUT _cluster/settings
{
  "persistent": {
    "cluster.remote.eu-cluster.skip_unavailable": true,
    "cluster.remote.us-cluster.skip_unavailable": false
  }
}

💡 İpucu: Production'da skip_unavailable: true genelde doğru seçim. Remote cluster'ın geçici kesintisi local sonuçları engellememelidir.


3. CCS Bağlantı Modları

Sniff Mode (Varsayılan)

Seed node'lara bağlanıp, cluster'daki tüm node'ları keşfeder:

PUT _cluster/settings
{
  "persistent": {
    "cluster.remote.eu-cluster.mode": "sniff",
    "cluster.remote.eu-cluster.seeds": [
      "eu-master-1:9300",
      "eu-master-2:9300"
    ],
    "cluster.remote.eu-cluster.node_connections": 3
  }
}

Proxy Mode

Bir proxy üzerinden bağlanır — cloud ve Kubernetes ortamlarında tercih edilir:

PUT _cluster/settings
{
  "persistent": {
    "cluster.remote.eu-cluster.mode": "proxy",
    "cluster.remote.eu-cluster.proxy_address": "eu-proxy.internal:9443",
    "cluster.remote.eu-cluster.server_name": "eu-cluster.elastic.internal",
    "cluster.remote.eu-cluster.num_proxy_sockets_per_connection": 18
  }
}
ModKullanımAvantaj
SniffOn-premise, doğrudan erişimDüşük latency, otomatik keşif
ProxyCloud, Kubernetes, firewall arkasıTek endpoint, güvenlik kolay

4. Cross-Cluster Replication (CCR)

CCR Nedir?

Bir cluster'daki (leader) index'in verilerini başka bir cluster'a (follower) otomatik kopyalar.

CCR Kullanım Senaryoları

SenaryoAçıklama
Disaster RecoveryPrimary cluster çökerse DR cluster devralır
Coğrafi yakınlıkKullanıcılar local cluster'dan okur → düşük latency
Centralized reportingHer bölgenin verisini merkeze kopyala → tek noktadan raporla
Read scalingYazma leader'da, okuma follower'lara dağıtılır

CCR Kurulumu

Adım 1: Remote Cluster Bağlantısı (Follower'da)

// Follower cluster'da leader cluster'ı tanımla
PUT _cluster/settings
{
  "persistent": {
    "cluster.remote.leader-cluster": {
      "seeds": ["leader-master-1:9300", "leader-master-2:9300"],
      "transport.compress": true
    }
  }
}

Adım 2: Leader Index'i Takip Et

// Follower cluster'da follow request
PUT /products-replica/_ccr/follow
{
  "remote_cluster": "leader-cluster",
  "leader_index": "products"
}

Bu komut:

  • products-replica adında bir follower index oluşturur

  • Leader cluster'daki products index'ini takip eder

  • Yeni document'lar otomatik kopyalanır

  • Follower index read-only olur

Adım 3: CCR Durumunu İzleme

// Follower index durumu
GET products-replica/_ccr/stats

// Yanıt:
{
  "indices": [
    {
      "index": "products-replica",
      "shards": [
        {
          "shard_id": 0,
          "leader_index": "products",
          "remote_cluster": "leader-cluster",
          "leader_global_checkpoint": 15000,
          "follower_global_checkpoint": 14998,
          "outstanding_read_requests": 2,
          "outstanding_write_requests": 1,
          "time_since_last_read_millis": 500,
          "operations_written": 14998,
          "bytes_read": 52428800
        }
      ]
    }
  ]
}

Auto-Follow Pattern

Yeni oluşturulan index'leri otomatik takip et:

// Leader'da logs-* pattern'ına uyan her yeni index otomatik takip edilsin
PUT _ccr/auto_follow/logs-pattern
{
  "remote_cluster": "leader-cluster",
  "leader_index_patterns": ["logs-*"],
  "follow_index_pattern": "{{leader_index}}-replica",
  "settings": {
    "index.number_of_replicas": 0
  }
}

// Auto-follow pattern'ları listele
GET _ccr/auto_follow

// Pattern sil
DELETE _ccr/auto_follow/logs-pattern

CCR İleri Ayarlar

PUT /products-replica/_ccr/follow
{
  "remote_cluster": "leader-cluster",
  "leader_index": "products",
  "settings": {
    "index.number_of_replicas": 0
  },
  "max_read_request_operation_count": 5120,
  "max_outstanding_read_requests": 12,
  "max_read_request_size": "32mb",
  "max_write_request_operation_count": 5120,
  "max_write_request_size": "9223372036854775807b",
  "max_outstanding_write_requests": 9,
  "max_write_buffer_count": 2147483647,
  "max_write_buffer_size": "512mb",
  "max_retry_delay": "500ms",
  "read_poll_timeout": "1m"
}

CCR'ı Durdurma ve Devam Ettirme

// Takibi duraklat
POST products-replica/_ccr/pause_follow

// Takibe devam et
POST products-replica/_ccr/resume_follow
{
  "max_read_request_operation_count": 5120
}

// Takibi tamamen sonlandır (follower'ı normal index'e çevir)
POST products-replica/_ccr/unfollow
// ⚠️ Önce pause yapılmalı!

5. Bi-Directional Replication (Çift Yönlü)

Bazı senaryolarda her cluster'ın hem reader hem writer olması gerekir:

Cluster A (Istanbul)           Cluster B (London)
┌──────────────┐              ┌──────────────┐
│ products-ist │ ──CCR──→     │ products-ist │ (follower, read-only)
│ (leader)     │              │              │
│              │              │              │
│ products-lon │ ←──CCR──     │ products-lon │ (leader)
│ (follower)   │              │              │
└──────────────┘              └──────────────┘
// Cluster A'da: London cluster'ını tanımla
PUT _cluster/settings
{
  "persistent": {
    "cluster.remote.london-cluster": {
      "seeds": ["lon-master-1:9300", "lon-master-2:9300"]
    }
  }
}

// London'dan products-lon'u takip et
PUT products-lon-replica/_ccr/follow
{
  "remote_cluster": "london-cluster",
  "leader_index": "products-lon"
}

// Cluster B'de: Istanbul cluster'ını tanımla ve products-ist'i takip et
// (aynı mantık, tersine)

Uygulama katmanında routing gerekir:

  • Istanbul kullanıcıları → products-ist'e yazar, products-ist + products-lon-replica'dan okur

  • London kullanıcıları → products-lon'a yazar, products-lon + products-ist-replica'dan okur


6. CCS Performans Optimizasyonu

ccs_minimize_roundtrips

// Minimize roundtrips — daha az network call, daha büyük response
GET logs-*,eu-cluster:logs-*/_search?ccs_minimize_roundtrips=true
{
  "query": { "match": { "message": "error" } },
  "size": 20
}

ccs_minimize_roundtrips=true (varsayılan) ile:

  • Tek round-trip: Local cluster sorguyu gönderir, remote tüm sonuçları döner

  • Dezavantaj: Remote cluster'da daha fazla iş yapılır

ccs_minimize_roundtrips=false ile:

  • İki round-trip: İlk tur shard'ları sorgular, ikinci tur fetch yapar

  • Avantaj: Daha az veri transfer edilir (sadece top-N fetch edilir)

Async CCS

// Büyük CCS sorguları async çalıştır
POST logs-*,eu-cluster:logs-*/_async_search
{
  "query": {
    "bool": {
      "filter": [
        { "range": { "@timestamp": { "gte": "now-7d" } } }
      ]
    }
  },
  "size": 100,
  "sort": [{ "@timestamp": "desc" }],
  "wait_for_completion_timeout": "5s"
}

// Sonucu al
GET _async_search/<async_search_id>

// Tüm partial results döndür
GET _async_search/<async_search_id>?wait_for_completion_timeout=30s

7. Disaster Recovery Senaryosu

Active-Passive DR

Primary Cluster (Istanbul)          DR Cluster (Frankfurt)
┌─────────────────────┐            ┌─────────────────────┐
│ 3 Master            │            │ 3 Master            │
│ 5 Hot Data          │ ──CCR──→   │ 3 Data              │
│ 3 Warm Data         │            │                     │
│ (Read + Write)      │            │ (Read-only)         │
└─────────────────────┘            └─────────────────────┘
// DR cluster'da auto-follow pattern
PUT _ccr/auto_follow/disaster-recovery
{
  "remote_cluster": "primary-cluster",
  "leader_index_patterns": ["*"],
  "leader_index_exclusion_patterns": [".security*", ".kibana*", ".monitoring*"],
  "follow_index_pattern": "{{leader_index}}",
  "settings": {
    "index.number_of_replicas": 1
  }
}

Failover Prosedürü

Primary cluster çöktüğünde:

// DR cluster'da tüm follower index'leri durdur ve unfollow yap
// Bu, index'leri writable yapar

// 1. Tüm CCR takiplerini listele
GET _ccr/stats

// 2. Her follower index için:
POST products/_ccr/pause_follow
POST products/_ccr/unfollow

// 3. Artık DR cluster yazılabilir — uygulamayı DR cluster'a yönlendir

// 4. Primary cluster geri geldiğinde:
// - Eski leader'ı follower yap (ters CCR)
// - Veya reindex ile senkronize et

Java ile DR Failover

public class DisasterRecoveryManager {
    private final ElasticsearchClient drClient;

    public DisasterRecoveryManager(ElasticsearchClient drClient) {
        this.drClient = drClient;
    }

    public void failover(List<String> followerIndices) throws Exception {
        for (String index : followerIndices) {
            try {
                // 1. Pause follow
                drClient.ccr().pauseFollow(p -> p.index(index));
                System.out.println("Paused: " + index);

                // 2. Close index (unfollow requires this)
                drClient.indices().close(c -> c.index(index));

                // 3. Unfollow (makes index writable)
                drClient.ccr().unfollow(u -> u.index(index));

                // 4. Open index
                drClient.indices().open(o -> o.index(index));

                System.out.println("Failover complete for: " + index);
            } catch (Exception e) {
                System.err.println("Failover failed for " + index +
                    ": " + e.getMessage());
            }
        }
        System.out.println("DR Failover completed!");
    }
}

8. Multi-Cluster Monitoring

Her Cluster'ın Sağlığını Kontrol

// Local cluster health
GET _cluster/health

// Remote cluster health (CCS üzerinden)
GET eu-cluster:_cluster/health
// ⚠️ Bu doğrudan çalışmaz — remote cluster'a ayrı bağlantı gerekir

// Remote cluster bağlantı durumu
GET _remote/info

CCR Lag Monitoring

// Tüm follower'ların replikasyon durumu
GET _ccr/stats

// Önemli metrikler:
// - leader_global_checkpoint vs follower_global_checkpoint → Fark = lag
// - time_since_last_read_millis → Yüksekse replikasyon yavaş
// - failed_read_requests → Bağlantı sorunu
// - failed_write_requests → Yazma sorunu

Watcher ile CCR Lag Alert

PUT _watcher/watch/ccr-lag-alert
{
  "trigger": {
    "schedule": { "interval": "1m" }
  },
  "input": {
    "http": {
      "request": {
        "host": "localhost",
        "port": 9200,
        "path": "/_ccr/stats",
        "scheme": "https",
        "auth": {
          "basic": {
            "username": "elastic",
            "password": "changeme"
          }
        }
      }
    }
  },
  "condition": {
    "script": {
      "source": """
        for (idx in ctx.payload.follow_stats.indices) {
          for (shard in idx.shards) {
            def lag = shard.leader_global_checkpoint - shard.follower_global_checkpoint;
            if (lag > 10000) return true;
          }
        }
        return false;
      """
    }
  },
  "actions": {
    "notify_ops": {
      "webhook": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
        "body": "{\"text\": \"⚠️ CCR replication lag detected! Check _ccr/stats\"}"
      }
    }
  }
}

9. Best Practices

✅ Yap

KonuÖneri
CCS skip_unavailabletrue — remote çökse bile local sonuçlar dönsün
CCR auto-followPattern ile yeni index'ler otomatik takip edilsin
DR clusterFarklı bölgede, farklı cloud provider'da
MonitoringCCR lag'ı sürekli izle, alert kur
NetworkCluster'lar arası düşük latency, yüksek bandwidth
GüvenlikTLS, API key veya certificate-based auth

❌ Yapma

KonuNeden
CCS ile ağır aggregation (yüksek latency)Network overhead, timeout riski
CCR'ı backup yerine kullanmaCCR silmeleri de replike eder — yanlışlıkla silinen veri her iki tarafta da kaybolur
skip_unavailable: false (default dışı)Remote çökünce tüm sorgular hata verir
Follower index'e yazmaRead-only — hata alırsınız
DR test yapmamakFailover prosedürünü yılda en az 2 kez test edin

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

Hata 1: "Remote Cluster Not Connected"

// Kontrol
GET _remote/info
// connected: false

// Olası nedenler:
// 1. Seed node'lar erişilebilir değil (firewall)
// 2. Transport port (9300) kapalı
// 3. Cluster adı uyuşmuyor

// Çözüm:
// Firewall kurallarını kontrol et
// Transport port açık mı: telnet eu-master-1 9300
// Seed node'ları güncelle:
PUT _cluster/settings
{
  "persistent": {
    "cluster.remote.eu-cluster.seeds": [
      "eu-master-1:9300",
      "eu-master-2:9300",
      "eu-master-3:9300"
    ]
  }
}

Hata 2: "CCR Follower Falling Behind"

// Sorun: Follower, leader'ın gerisinde kalıyor
// Kontrol:
GET _ccr/stats?filter_path=follow_stats.indices.*.shards.*.leader_global_checkpoint,follow_stats.indices.*.shards.*.follower_global_checkpoint

// Çözümler:
// 1. Write buffer artır
POST products-replica/_ccr/resume_follow
{
  "max_write_buffer_size": "1gb",
  "max_outstanding_read_requests": 24,
  "max_outstanding_write_requests": 18
}

// 2. Network bandwidth kontrol
// 3. Follower cluster yetişemiyorsa, daha fazla data node ekle

Hata 3: "CCS Timeout"

// Sorun: CCS sorgusu timeout'a düşüyor
// Çözüm 1: Timeout artır
GET eu-cluster:logs-*/_search?timeout=60s
{
  "query": { "match": { "message": "error" } }
}

// Çözüm 2: Minimize roundtrips
GET eu-cluster:logs-*/_search?ccs_minimize_roundtrips=true
{
  "query": { "match": { "message": "error" } }
}

// Çözüm 3: Async search kullan
POST eu-cluster:logs-*/_async_search
{
  "query": { "match": { "message": "error" } },
  "wait_for_completion_timeout": "5s"
}

Hata 4: "Cannot Write to Follower Index"

// Sorun: Follower index'e yazma denemesi
// "index [products-replica] blocked by: [FORBIDDEN/..."

// Bu beklenen davranış — follower read-only'dir
// Yazma yapmak için:
// 1. Pause follow
POST products-replica/_ccr/pause_follow

// 2. Unfollow (artık bağımsız index)
POST products-replica/_ccr/unfollow

// 3. Artık yazılabilir
POST products-replica/_doc
{
  "name": "New Product"
}

// ⚠️ Unfollow kalıcıdır — tekrar follow yapamazsınız, yeni follow kurmalısınız

11. CCS ve CCR Versiyon Uyumluluğu

Local/LeaderRemote/FollowerCCSCCR
8.x8.x
8.x7.last
7.x7.x
8.x7.17+✅ (one-way)

⚠️ Dikkat: CCS farklı major versiyonlar arası çalışabilir (sınırlı), ama CCR genelde aynı major versiyonda çalışır. Versiyon uyumluluğunu daima Elastic dokümantasyonundan kontrol edin.


Özet

  1. Cross-Cluster Search (CCS) birden fazla cluster'ı tek sorgu ile arayabilmenizi sağlar — <cluster>:<index> formatıyla remote index'lere erişirsiniz.

  2. Cross-Cluster Replication (CCR) bir cluster'daki veriyi otomatik olarak başka bir cluster'a kopyalar — disaster recovery ve coğrafi yakınlık için kritiktir.

  3. `skip_unavailable: true` production'da olmazsa olmaz — remote cluster çökse bile local sonuçlar dönmeye devam eder.

  4. Auto-follow pattern ile yeni oluşturulan index'ler otomatik CCR takibine alınır — ILM rollover ile birlikte kullanıldığında tamamen otomatik.

  5. DR failover prosedürü net olmalı — pause → close → unfollow → open sırası izlenir. Bu prosedürü yılda en az iki kez test edin.

  6. CCR backup değildir! Silme işlemleri de replike edilir. Gerçek backup için snapshot/restore kullanın.