Elasticsearch Cross-Cluster Search ile Çoklu Küme Sorgulama
Büyük ölçekli Elasticsearch altyapılarında en sık karşılaşılan sorunlardan biri, farklı cluster’larda dağılmış verileri tek bir sorguyla çekme ihtiyacıdır. Birden fazla veri merkezi, farklı ortamlar (dev/staging/prod) veya coğrafi olarak ayrılmış cluster’lar söz konusu olduğunda, Cross-Cluster Search (CCS) bu sorunu zarif bir şekilde çözüyor. Bu yazıda, gerçek dünya senaryolarıyla CCS kurulumunu, yapılandırmasını ve yönetimini ele alacağız.
Cross-Cluster Search Nedir ve Neden Kullanılır?
Cross-Cluster Search, Elasticsearch 5.3 ile tanıtılan ve birden fazla cluster üzerinde tek bir API çağrısıyla sorgu yapmanıza olanak tanıyan bir özelliktir. Standart bir Elasticsearch kurulumunda tüm node’lar aynı cluster’a aittir ve veri bu cluster içinde shard’lara dağıtılır. Ancak şu senaryolarda bu yapı yetersiz kalır:
- Çok bölgeli mimari: İstanbul ve Frankfurt’ta ayrı cluster’larınız var ve her ikisindeki log verilerini birlikte analiz etmeniz gerekiyor.
- Ortam izolasyonu: Production ve staging verilerini izole cluster’larda tutuyorsunuz ama karşılaştırmalı analiz yapmanız gerekiyor.
- Tenant izolasyonu: Her müşteri için ayrı cluster kuruyorsunuz ama merkezi bir reporting dashboard’u beslemeniz gerekiyor.
- Felaket kurtarma: Cross-Cluster Replication ile birleştirildiğinde, primary cluster çökse bile secondary cluster üzerinden sorgulama yapabiliyorsunuz.
CCS’nin alternatifi olan “her şeyi tek cluster’a koy” yaklaşımı, belirli bir ölçeğin ötesinde hem maliyet hem de operasyonel karmaşıklık açısından sürdürülemez hale gelir. CCS ise cluster’ların bağımsızlığını korurken sorgu federasyonu sağlar.
Mimari Genel Bakış
CCS mimarisinde iki temel rol vardır:
- Local cluster (koordinatör): Sorguyu başlatan cluster. Kullanıcının bağlandığı yer burasıdır.
- Remote cluster: Sorgunun gönderildiği uzak cluster’lar. Bunlar read-only erişime açılır.
Local cluster, sorguyu remote cluster’lara iletir, sonuçları toplar ve birleştirerek istemciye döndürür. Bu işlem sırasında local cluster’daki koordinatör node, remote cluster’lardaki node’larla doğrudan iletişim kurar.
İki bağlantı modu mevcuttur:
- Sniff mode: Local cluster, remote cluster’ın seed node’larına bağlanır ve cluster topology’sini keşfeder. Daha esnek ama firewall geçişi gerektirir.
- Proxy mode: Tüm bağlantılar tek bir proxy endpoint üzerinden geçer. Güvenlik açısından kontrol edilmesi daha kolaydır.
Ön Gereksinimler ve Ortam Hazırlığı
Bu yazıdaki örneklerde üç cluster kullanacağız:
- cluster-local: 192.168.1.10 (koordinatör)
- cluster-istanbul: 192.168.1.20 (remote 1)
- cluster-frankfurt: 192.168.1.30 (remote 2)
Her cluster’ın Elasticsearch versiyonu uyumlu olmalıdır. Resmi kural şudur: remote cluster versiyonu, local cluster versiyonundan daha yeni olamaz. Genellikle aynı major versiyon içinde kalmak en sağlıklısı.
Önce her node’un elasticsearch.yml dosyasını doğru yapılandırdığımızdan emin olalım:
# /etc/elasticsearch/elasticsearch.yml - cluster-local için
cluster.name: cluster-local
node.name: local-node-1
network.host: 192.168.1.10
http.port: 9200
transport.port: 9300
# Remote cluster bağlantıları için transport portu açık olmalı
transport.host: 192.168.1.10
Aynı yapılandırmayı diğer cluster’lar için de uygulayın, sadece cluster.name ve network.host değerlerini değiştirin.
Firewall tarafında transport portunun (varsayılan 9300) açık olması gerekiyor:
# Her cluster'ın firewall'unda diğer cluster'ların transport portuna izin ver
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="9300" protocol="tcp" accept'
firewall-cmd --reload
# Bağlantıyı test et
nc -zv 192.168.1.20 9300
nc -zv 192.168.1.30 9300
Remote Cluster Tanımlama
Remote cluster’ları tanımlamanın iki yolu var: elasticsearch.yml üzerinden statik yapılandırma veya Cluster Settings API üzerinden dinamik yapılandırma. Dinamik yöntemi tercih ediyorum çünkü cluster’ı yeniden başlatmadan değişiklik yapabiliyorsunuz.
Sniff Mode ile Remote Cluster Ekleme
# Local cluster üzerinden remote cluster'ları tanımla
curl -X PUT "http://192.168.1.10:9200/_cluster/settings"
-H "Content-Type: application/json"
-d '{
"persistent": {
"cluster": {
"remote": {
"istanbul": {
"seeds": ["192.168.1.20:9300"],
"transport.ping_schedule": "30s",
"transport.compress": true,
"skip_unavailable": true
},
"frankfurt": {
"seeds": ["192.168.1.30:9300"],
"transport.ping_schedule": "30s",
"transport.compress": true,
"skip_unavailable": true
}
}
}
}
}'
Burada skip_unavailable: true kritik bir ayar. Bu sayede remote cluster erişilemez olduğunda sorgu tamamen başarısız olmak yerine mevcut cluster’lardan veriyi döndürür. Production ortamında mutlaka true yapın.
Proxy Mode ile Remote Cluster Ekleme
Eğer ortamınızda firewall kısıtlamaları varsa proxy mode daha uygun:
curl -X PUT "http://192.168.1.10:9200/_cluster/settings"
-H "Content-Type: application/json"
-d '{
"persistent": {
"cluster": {
"remote": {
"istanbul-proxy": {
"mode": "proxy",
"proxy_address": "proxy.istanbul.internal:9300",
"skip_unavailable": true
}
}
}
}
}'
Bağlantı Durumunu Doğrulama
# Remote cluster bağlantılarının durumunu kontrol et
curl -X GET "http://192.168.1.10:9200/_remote/info" | python3 -m json.tool
# Beklenen çıktı şuna benzer:
# {
# "istanbul": {
# "connected": true,
# "mode": "sniff",
# "num_nodes_connected": 1,
# "max_connections_per_cluster": 3,
# "initial_connect_timeout": "30s",
# "skip_unavailable": true
# }
# }
Cross-Cluster Search Sorguları
Remote cluster’lar tanımlandıktan sonra sorgu yapmak son derece basit. Sözdizimi şu şekilde: :.
Temel CCS Sorgusu
# Tek remote cluster üzerinde sorgulama
curl -X GET "http://192.168.1.10:9200/istanbul:nginx-logs-*/_search"
-H "Content-Type: application/json"
-d '{
"query": {
"range": {
"@timestamp": {
"gte": "now-1h",
"lte": "now"
}
}
},
"size": 10
}'
Birden Fazla Cluster Üzerinde Eş Zamanlı Sorgulama
# Local cluster + iki remote cluster üzerinde aynı anda sorgula
curl -X GET "http://192.168.1.10:9200/nginx-logs-*,istanbul:nginx-logs-*,frankfurt:nginx-logs-*/_search"
-H "Content-Type: application/json"
-d '{
"query": {
"bool": {
"must": [
{
"range": {
"@timestamp": {
"gte": "now-24h",
"lte": "now"
}
}
},
{
"term": {
"status": "500"
}
}
]
}
},
"aggs": {
"errors_per_cluster": {
"terms": {
"field": "_index",
"size": 20
}
}
},
"size": 0
}'
Bu sorgu çok kullanışlı bir pattern. Tüm cluster’lardaki HTTP 500 hatalarını tek seferde çekiyor ve _index alanı üzerinden hangi cluster’dan geldiğini ayırt edebiliyorsunuz.
Wildcard ile Dinamik Cluster Seçimi
# Tüm remote cluster'larda wildcard ile index sorgulama
curl -X GET "http://192.168.1.10:9200/*:nginx-logs-2024.*/_search"
-H "Content-Type: application/json"
-d '{
"query": {
"match": {
"message": "connection refused"
}
},
"_source": ["@timestamp", "host", "message", "status"],
"sort": [{"@timestamp": {"order": "desc"}}],
"size": 50
}'
: prefix’i tanımlı tüm remote cluster’ları hedef alır. Local cluster’ı da dahil etmek istiyorsanız nginx-logs-2024.,:nginx-logs-2024. şeklinde yazın.
Güvenlik Yapılandırması
Elasticsearch Security aktifse (ki production’da olmalı), CCS için özel yapılandırma gerekir. X-Pack Security veya OpenSearch Security kullanıyorsanız bu adımları uygulayın.
TLS Yapılandırması
# elasticsearch.yml - tüm cluster'larda
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /etc/elasticsearch/certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /etc/elasticsearch/certs/elastic-certificates.p12
Remote Cluster için Kullanıcı ve Rol Tanımlama
Local cluster’daki kullanıcının remote cluster’a erişebilmesi için remote cluster üzerinde de bir kullanıcı tanımlanması gerekir. Elasticsearch 8.x’te API Key tabanlı authentication önerilen yöntem:
# Remote cluster (istanbul) üzerinde API key oluştur
curl -X POST "http://192.168.1.20:9200/_security/api_key"
-H "Content-Type: application/json"
-u "elastic:your_password"
-d '{
"name": "ccs-readonly-key",
"role_descriptors": {
"ccs_reader": {
"cluster": ["cross_cluster_search"],
"indices": [
{
"names": ["nginx-logs-*", "app-logs-*"],
"privileges": ["read", "view_index_metadata"]
}
]
}
}
}'
API Key’i local cluster’a tanımlayın:
curl -X PUT "http://192.168.1.10:9200/_cluster/settings"
-H "Content-Type: application/json"
-u "elastic:local_password"
-d '{
"persistent": {
"cluster.remote.istanbul.credentials": "BASE64_ENCODED_API_KEY"
}
}'
Gerçek Dünya Senaryosu: Merkezi Log Analizi
Şirketimizin İstanbul ve Frankfurt data center’larında ayrı Elasticsearch cluster’ları var. Her iki lokasyondaki web sunucularından gelen nginx loglarını merkezi Kibana’dan analiz etmek istiyoruz.
Önce her cluster’da aynı index mapping’ini oluşturalım:
# Her iki remote cluster'da da bu template'i uygula
curl -X PUT "http://192.168.1.20:9200/_index_template/nginx-logs"
-H "Content-Type: application/json"
-d '{
"index_patterns": ["nginx-logs-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.lifecycle.name": "nginx-ilm-policy"
},
"mappings": {
"properties": {
"@timestamp": {"type": "date"},
"host": {"type": "keyword"},
"status": {"type": "integer"},
"bytes": {"type": "long"},
"response_time": {"type": "float"},
"remote_addr": {"type": "ip"},
"datacenter": {"type": "keyword"}
}
}
}
}'
Şimdi tüm cluster’larda response time analizi yapan bir sorgu yazalım:
# Tüm lokasyonlardaki yavaş istekleri bul ve lokasyona göre grupla
curl -X GET "http://192.168.1.10:9200/nginx-logs-*,istanbul:nginx-logs-*,frankfurt:nginx-logs-*/_search"
-H "Content-Type: application/json"
-d '{
"query": {
"bool": {
"must": [
{"range": {"@timestamp": {"gte": "now-6h"}}},
{"range": {"response_time": {"gte": 2.0}}}
]
}
},
"aggs": {
"by_datacenter": {
"terms": {
"field": "datacenter",
"size": 10
},
"aggs": {
"avg_response": {
"avg": {"field": "response_time"}
},
"p95_response": {
"percentiles": {
"field": "response_time",
"percents": [95, 99]
}
},
"error_rate": {
"filter": {
"range": {"status": {"gte": 500}}
}
}
}
}
},
"size": 0
}'
Bu sorgu son 6 saatteki 2 saniyenin üzerindeki istekleri tüm data center’lardan çekiyor ve ortalama response time ile 95/99 persentil değerlerini hesaplıyor.
Performans Optimizasyonu
CCS sorgularında performans, network latency ve veri hacmine bağlı olarak büyük farklılıklar gösterebilir. Şu optimizasyonları uygulayın:
ccs_minimize_roundtrips: Varsayılan olaraktruegelir, remote cluster’larla round-trip sayısını azaltır. Aggregation ağırlıklı sorgularda bazenfalsedaha iyi performans verir ama genel olarak varsayılanı kullanın.- Shard sayısını dengeleme: Remote cluster’larda gereksiz yere fazla shard açmayın. CCS sorgusunda her shard ayrı bir iş birimi oluşturur.
_sourcefiltreleme: Tüm alanları çekmek yerine sadece ihtiyaç duyduğunuz alanları belirtin. Network trafiğini önemli ölçüde azaltır.- Index pattern hassasiyeti:
:gibi genel pattern’lar yerineistanbul:nginx-logs-2024.*gibi spesifik pattern’lar kullanın.
Sorgu performansını ölçmek için ?explain=true parametresini kullanabilirsiniz:
# Sorgu planını ve shard dağılımını görüntüle
curl -X GET "http://192.168.1.10:9200/istanbul:nginx-logs-*/_search?explain=true"
-H "Content-Type: application/json"
-d '{
"query": {"match_all": {}},
"size": 1
}'
Sorun Giderme
CCS ile çalışırken en sık karşılaşılan sorunlar şunlar:
connect_exception: Transport portu (9300) firewall tarafında bloke edilmiştir.nc -zvile test edin.SearchPhaseExecutionException: Genellikle remote cluster’daki shard’lardan birinin erişilemez olmasından kaynaklanır.skip_unavailable: trueayarını kontrol edin.- Versiyon uyumsuzluğu: Cluster versiyonlarını kontrol edin.
GET /endpoint’i her cluster’ın versiyonunu döndürür. security_exception: Remote cluster’daki kullanıcı/API key’in ilgili index’lere erişim yetkisi yoktur.
Tanı için şu komutu çalıştırın:
# Remote cluster bağlantı detaylarını ve istatistiklerini görüntüle
curl -X GET "http://192.168.1.10:9200/_nodes/stats/transport" |
python3 -c "
import json, sys
data = json.load(sys.stdin)
for node_id, node in data['nodes'].items():
print(f"Node: {node['name']}")
print(f" TX: {node['transport']['tx_size_in_bytes']} bytes")
print(f" RX: {node['transport']['rx_size_in_bytes']} bytes")
"
Kibana ile CCS Entegrasyonu
Kibana üzerinden CCS kullanmak için kibana.yml dosyasına ek bir yapılandırma gerekmez. Kibana, local Elasticsearch cluster’ına bağlıdır ve CCS sorgularını otomatik olarak yönetir.
Index pattern oluştururken remote cluster prefix’ini kullanın. Kibana’da “Stack Management > Data Views” kısmına gidip istanbul:nginx-logs-,frankfurt:nginx-logs- şeklinde bir data view oluşturmanız yeterli. Kibana bu pattern’ı CCS sorgusu olarak yorumlar.
Dashboard’larınızda farklı cluster’ları aynı grafikte göstermek için datacenter gibi bir alan üzerinden renkli görselleştirmeler oluşturabilirsiniz.
Sonuç
Cross-Cluster Search, dağıtık Elasticsearch altyapılarında veri silosu sorununu çözmenin en pratik yoludur. Kurulumu görece basit, operasyonel maliyeti düşük ve ölçeklenebilirliği yüksek bir özelliktir.
Özetlemek gerekirse:
- Remote cluster’ları dinamik API ile tanımlayın, statik yapılandırmadan kaçının.
skip_unavailable: trueayarını production’da mutlaka kullanın.- Güvenlik için API key tabanlı authentication’ı tercih edin.
- Sorgu performansını index pattern hassasiyeti ve
_sourcefiltrelemesi ile optimize edin. - Kibana entegrasyonu için ekstra yapılandırma gerekmez, data view pattern’ı yeterlidir.
CCS’yi Cross-Cluster Replication (CCR) ile birleştirirseniz hem yüksek erişilebilirlik hem de okuma yükü dağıtımı elde edersiniz. Bu iki özellik birlikte kullanıldığında gerçek anlamda global ölçekte bir Elasticsearch mimarisi kurmuş olursunuz.
