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 recovery | Primary + DR cluster, CCR ile replikasyon |
| Organizasyonel izolasyon | Departman/takım bazlı cluster'lar |
| Versiyon bağımsızlığı | Farklı cluster'lar farklı versiyonlarda olabilir |
| Compliance | Veri 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
| Özellik | Tek Cluster | Multi-Cluster |
|---|---|---|
| Yönetim | Basit | Karmaşık |
| Latency | Düşük (aynı DC) | Bölgeler arası yüksek |
| HA | Node seviyesinde | Cluster seviyesinde |
| Scaling | Sınırlı | Sınırsız |
| Compliance | Zor | Kolay (bölgesel veri) |
2. Cross-Cluster Search (CCS) — Uzaktan Arama
CCS Nasıl Çalışır?
Local cluster, uzak cluster'a bağlantı kurar
Sorgu hem local hem remote cluster'da çalışır
Sonuçlar local cluster'da birleştirilir
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: truegenelde 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
}
}| Mod | Kullanım | Avantaj |
|---|---|---|
| Sniff | On-premise, doğrudan erişim | Düşük latency, otomatik keşif |
| Proxy | Cloud, 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ı
| Senaryo | Açıklama |
|---|---|
| Disaster Recovery | Primary cluster çökerse DR cluster devralır |
| Coğrafi yakınlık | Kullanıcılar local cluster'dan okur → düşük latency |
| Centralized reporting | Her bölgenin verisini merkeze kopyala → tek noktadan raporla |
| Read scaling | Yazma 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-replicaadında bir follower index oluştururLeader cluster'daki
productsindex'ini takip ederYeni 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-patternCCR İ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 okurLondon 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=30s7. 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 etJava 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/infoCCR 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 sorunuWatcher 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_unavailable | true — remote çökse bile local sonuçlar dönsün |
| CCR auto-follow | Pattern ile yeni index'ler otomatik takip edilsin |
| DR cluster | Farklı bölgede, farklı cloud provider'da |
| Monitoring | CCR lag'ı sürekli izle, alert kur |
| Network | Cluster'lar arası düşük latency, yüksek bandwidth |
| Güvenlik | TLS, API key veya certificate-based auth |
❌ Yapma
| Konu | Neden |
|---|---|
| CCS ile ağır aggregation (yüksek latency) | Network overhead, timeout riski |
| CCR'ı backup yerine kullanma | CCR 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 yazma | Read-only — hata alırsınız |
| DR test yapmamak | Failover 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 ekleHata 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ız11. CCS ve CCR Versiyon Uyumluluğu
| Local/Leader | Remote/Follower | CCS | CCR |
|---|---|---|---|
| 8.x | 8.x | ✅ | ✅ |
| 8.x | 7.last | ✅ | ❌ |
| 7.x | 7.x | ✅ | ✅ |
| 8.x | 7.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
Cross-Cluster Search (CCS) birden fazla cluster'ı tek sorgu ile arayabilmenizi sağlar —
<cluster>:<index>formatıyla remote index'lere erişirsiniz.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.
`skip_unavailable: true` production'da olmazsa olmaz — remote cluster çökse bile local sonuçlar dönmeye devam eder.
Auto-follow pattern ile yeni oluşturulan index'ler otomatik CCR takibine alınır — ILM rollover ile birlikte kullanıldığında tamamen otomatik.
DR failover prosedürü net olmalı — pause → close → unfollow → open sırası izlenir. Bu prosedürü yılda en az iki kez test edin.
CCR backup değildir! Silme işlemleri de replike edilir. Gerçek backup için snapshot/restore kullanın.
AI Asistan
Sorularını yanıtlamaya hazır