← Kursa Dön
📄 Text · 40 min

Gerçek Dünya Mimarileri — E-Commerce, Log, APM, SIEM

Giriş — Teoriden Pratiğe

Buraya kadar Elasticsearch'ün tüm yapı taşlarını öğrendin: index, mapping, query, aggregation, cluster yönetimi, güvenlik, backup. Şimdi tüm bu bilgileri birleştirip gerçek dünya senaryolarında nasıl kullanıldığını göreceğiz.

Bir LEGO kutusunu düşün. Tek tek parçaları tanıyorsun — ama asıl mesele onlardan bir ev, bir araba veya bir kale yapabilmek. Bu ders tam da o: dört farklı gerçek dünya senaryosunda, production seviyesinde mimari tasarımlar.

Her senaryo için şunları ele alacağız:

  • Mimari diyagram açıklaması ve node yapısı

  • Shard stratejisi ve sizing

  • Mapping tasarımı

  • Örnek query'ler

  • Java/Spring Boot entegrasyonu (uygun yerlerde)


Senaryo 1: E-Commerce Arama Platformu

Problem Tanımı

Bir e-commerce sitesi: 5 milyon ürün, günlük 2 milyon arama, autocomplete, faceted search (filtreler), ürün önerileri. Kullanıcılar "kırmızı nike ayakkabı 42 numara" yazıp anında sonuç bekliyor.

Mimari

Kullanıcılar (Web + Mobile)
         │
    Load Balancer
         │
  ┌──────┼──────┐
  API GW  API GW  API GW  (Spring Boot x3)
  └──────┼──────┘
         │
  ┌──────┼──────┐
  Coord-1 Coord-2 Coord-3  (coordinating only)
  └──────┼──────┘
         │
  ┌──────┼──────┐
  Data-1  Data-2  Data-3   (hot data nodes)
  └──────┴──────┘
  + 3 dedicated master node

Node Yapısı — 9 Node

NodeRolSayıSpec
MasterDedicated master34 CPU, 8GB RAM, 50GB SSD
CoordinatingSearch load balancing38 CPU, 16GB RAM
Data (Hot)Ürün verileri, arama316 CPU, 64GB RAM, 1TB NVMe SSD

Shard Stratejisi

  • products index: 3 primary, 1 replica = 6 shard (3 data node'a eşit dağılım)

  • products-suggestions (autocomplete): 1 primary, 2 replica (küçük ama yoğun okunan index — her node'da bir kopya)

  • Günlük arama logları: ILM ile rollover, hot → delete (30 gün)

Mapping — Ürün Index'i

PUT products
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "turkish_custom": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "turkish_stemmer", "turkish_stop"]
        },
        "autocomplete_analyzer": {
          "type": "custom",
          "tokenizer": "autocomplete_tokenizer",
          "filter": ["lowercase"]
        },
        "autocomplete_search": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase"]
        }
      },
      "tokenizer": {
        "autocomplete_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 15,
          "token_chars": ["letter", "digit"]
        }
      },
      "filter": {
        "turkish_stemmer": {
          "type": "stemmer",
          "language": "turkish"
        },
        "turkish_stop": {
          "type": "stop",
          "stopwords": "_turkish_"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "turkish_custom",
        "fields": {
          "keyword": { "type": "keyword" },
          "autocomplete": {
            "type": "text",
            "analyzer": "autocomplete_analyzer",
            "search_analyzer": "autocomplete_search"
          }
        }
      },
      "description": {
        "type": "text",
        "analyzer": "turkish_custom"
      },
      "brand": {
        "type": "keyword",
        "fields": {
          "text": { "type": "text", "analyzer": "turkish_custom" }
        }
      },
      "category": {
        "type": "keyword"
      },
      "category_path": {
        "type": "keyword"
      },
      "price": { "type": "scaled_float", "scaling_factor": 100 },
      "original_price": { "type": "scaled_float", "scaling_factor": 100 },
      "discount_percent": { "type": "byte" },
      "currency": { "type": "keyword" },
      "in_stock": { "type": "boolean" },
      "stock_count": { "type": "integer" },
      "rating": { "type": "half_float" },
      "review_count": { "type": "integer" },
      "color": { "type": "keyword" },
      "size": { "type": "keyword" },
      "tags": { "type": "keyword" },
      "images": { "type": "keyword", "index": false },
      "created_at": { "type": "date" },
      "updated_at": { "type": "date" },
      "attributes": {
        "type": "nested",
        "properties": {
          "name": { "type": "keyword" },
          "value": { "type": "keyword" }
        }
      }
    }
  }
}

Arama Query'leri

Temel Ürün Arama (Faceted Search):

GET products/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "kırmızı nike ayakkabı",
            "fields": ["name^3", "name.autocomplete", "brand.text^2", "description", "tags"],
            "type": "best_fields",
            "fuzziness": "AUTO"
          }
        }
      ],
      "filter": [
        { "term": { "in_stock": true } },
        { "range": { "price": { "gte": 200, "lte": 1500 } } },
        { "terms": { "size": ["41", "42", "43"] } }
      ]
    }
  },
  "aggs": {
    "brands": {
      "terms": { "field": "brand", "size": 20 }
    },
    "categories": {
      "terms": { "field": "category", "size": 20 }
    },
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 100 },
          { "from": 100, "to": 300 },
          { "from": 300, "to": 500 },
          { "from": 500, "to": 1000 },
          { "from": 1000 }
        ]
      }
    },
    "colors": {
      "terms": { "field": "color", "size": 15 }
    },
    "avg_price": {
      "avg": { "field": "price" }
    },
    "rating_histogram": {
      "histogram": { "field": "rating", "interval": 1, "min_doc_count": 0 }
    }
  },
  "highlight": {
    "fields": {
      "name": {},
      "description": { "fragment_size": 150 }
    }
  },
  "size": 20,
  "from": 0
}

Autocomplete: name.autocomplete field'ına match query + in_stock filter + _source ile sadece gerekli field'ları döndürerek 8 öneri sunulur. Spring Boot service kodu aşağıda.

Spring Boot Entegrasyonu

Entity sınıfı @Document(indexName = "products") ile tanımlanır — name field'ında @MultiField ile keyword ve autocomplete alt-field'lar, brand/category keyword, price double, inStock boolean, rating half_float tipinde. Asıl önemli olan arama service'i:

@Service
public class ProductSearchService {

    private final ElasticsearchClient client;

    public ProductSearchService(ElasticsearchClient client) {
        this.client = client;
    }

    public SearchResponse<Product> search(String query, Map<String, List<String>> filters,
                                           double minPrice, double maxPrice,
                                           int page, int pageSize) throws Exception {

        return client.search(s -> s
            .index("products")
            .query(q -> q
                .bool(b -> {
                    // Full-text arama
                    b.must(m -> m
                        .multiMatch(mm -> mm
                            .query(query)
                            .fields("name^3", "brand^2", "description", "tags")
                            .fuzziness("AUTO")
                        )
                    );

                    // Stok filtresi
                    b.filter(f -> f.term(t -> t.field("in_stock").value(true)));

                    // Fiyat aralığı
                    b.filter(f -> f.range(r -> r
                        .field("price")
                        .gte(JsonData.of(minPrice))
                        .lte(JsonData.of(maxPrice))
                    ));

                    // Dinamik filtreler
                    if (filters.containsKey("brand")) {
                        b.filter(f -> f.terms(t -> t
                            .field("brand")
                            .terms(tv -> tv.value(
                                filters.get("brand").stream()
                                    .map(FieldValue::of)
                                    .collect(Collectors.toList())
                            ))
                        ));
                    }

                    return b;
                })
            )
            // Aggregation'lar (facet'ler)
            .aggregations("brands", a -> a
                .terms(t -> t.field("brand").size(20))
            )
            .aggregations("categories", a -> a
                .terms(t -> t.field("category").size(20))
            )
            .aggregations("price_ranges", a -> a
                .range(r -> r
                    .field("price")
                    .ranges(
                        rv -> rv.to("100"),
                        rv -> rv.from("100").to("300"),
                        rv -> rv.from("300").to("500"),
                        rv -> rv.from("500").to("1000"),
                        rv -> rv.from("1000")
                    )
                )
            )
            .aggregations("colors", a -> a
                .terms(t -> t.field("color").size(15))
            )
            // Highlight
            .highlight(h -> h
                .fields("name", hf -> hf)
                .fields("description", hf -> hf.fragmentSize(150))
            )
            .from(page * pageSize)
            .size(pageSize),
            Product.class
        );
    }

    // Autocomplete
    public List<Product> autocomplete(String prefix) throws Exception {
        SearchResponse<Product> response = client.search(s -> s
            .index("products")
            .query(q -> q
                .bool(b -> b
                    .must(m -> m
                        .match(mt -> mt
                            .field("name.autocomplete")
                            .query(prefix)
                            .operator(Operator.And)
                        )
                    )
                    .filter(f -> f.term(t -> t.field("in_stock").value(true)))
                )
            )
            .source(sc -> sc.filter(sf -> sf
                .includes("name", "brand", "price", "images")
            ))
            .size(8),
            Product.class
        );

        return response.hits().hits().stream()
            .map(Hit::source)
            .collect(Collectors.toList());
    }
}

Controller katmanı basit: @GetMapping("/products") ile searchService.search() çağrısı, @GetMapping("/autocomplete") ile searchService.autocomplete() çağrısı. Request parametreleri (query, minPrice, maxPrice, page, size, filters) doğrudan service'e iletilir.


Senaryo 2: Log Analytics — ELK Stack (100GB/gün)

Problem Tanımı

Bir teknoloji şirketi: 200+ mikro servis, günlük 100GB log, 90 gün saklama. Geliştiriciler hata ayıklama, operasyon ekibi alarm, yönetim raporlama istiyor.

Mimari

Mikroservisler (200+) → Filebeat agent
         │
    Logstash (x3) — Grok parsing, enrichment, routing
         │
  ┌──────┼──────────────────┐
  HOT (x3)    WARM (x3)    COLD (x2)
  NVMe SSD    HDD 64GB     HDD 32GB
  Son 7 gün   7-30 gün     30-90 gün
  └──────┴──────────────────┘
  + Master (x3) + Kibana (x2)

Node Yapısı — 14 Node

NodeRolSayıSpecDisk
MasterDedicated master34 CPU, 8GB RAM50GB SSD
HotData_hot, Ingest316 CPU, 64GB RAM2TB NVMe SSD
WarmData_warm38 CPU, 64GB RAM8TB HDD
ColdData_cold24 CPU, 32GB RAM16TB HDD
KibanaVisualization24 CPU, 8GB RAM-

Shard Stratejisi

  • Günlük index rollover: logs-<service>-YYYY.MM.dd

  • Hot: 3 primary, 1 replica (günlük ~100GB / 3 shard ≈ 33GB/shard — ideal)

  • Warm'a geçince: shrink 1 shard + force merge 1 segment

  • Cold'a geçince: searchable snapshot (frozen tier)

ILM Policy

PUT _ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50gb",
            "max_age": "1d",
            "max_docs": 500000000
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": { "number_of_shards": 1 },
          "forcemerge": { "max_num_segments": 1 },
          "allocate": {
            "number_of_replicas": 0,
            "require": { "_tier_preference": "data_warm" }
          },
          "set_priority": { "priority": 50 }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": {
            "require": { "_tier_preference": "data_cold" }
          },
          "set_priority": { "priority": 0 }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

Index Template

PUT _index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "data_stream": {},
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs_policy",
      "index.routing.allocation.require._tier_preference": "data_hot",
      "index.codec": "best_compression",
      "index.refresh_interval": "10s"
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "message": { "type": "text" },
        "level": { "type": "keyword" },
        "service": { "type": "keyword" },
        "environment": { "type": "keyword" },
        "host": { "type": "keyword" },
        "trace_id": { "type": "keyword" },
        "span_id": { "type": "keyword" },
        "user_id": { "type": "keyword" },
        "request_id": { "type": "keyword" },
        "http": {
          "properties": {
            "method": { "type": "keyword" },
            "status_code": { "type": "short" },
            "url": { "type": "keyword" },
            "duration_ms": { "type": "integer" }
          }
        },
        "error": {
          "properties": {
            "type": { "type": "keyword" },
            "message": { "type": "text" },
            "stack_trace": { "type": "text", "index": false }
          }
        }
      }
    }
  }
}

Logstash Pipeline (Özet)

# /etc/logstash/conf.d/logs.conf
input {
  beats { port => 5044; ssl => true }
}

filter {
  if [message] =~ /^\{/ { json { source => "message" } }
  if ![level] {
    grok {
      match => { "message" => "%{TIMESTAMP_ISO8601:@timestamp} %{LOGLEVEL:level} \[%{DATA:service}\] %{GREEDYDATA:log_message}" }
    }
  }
  date { match => ["@timestamp", "ISO8601"] }
  if [client_ip] { geoip { source => "client_ip" } }
  mutate { remove_field => ["agent", "ecs", "input", "log"] }
}

output {
  elasticsearch {
    hosts => ["https://es-hot-1:9200", "https://es-hot-2:9200"]
    data_stream => true
    data_stream_type => "logs"
    data_stream_dataset => "%{[service]}"
    data_stream_namespace => "production"
  }
}

Kibana Dashboard Query'leri

// Son 1 saatteki error sayısı — servis bazlı, zaman dağılımlı
GET logs-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "term": { "level": "ERROR" } },
        { "range": { "@timestamp": { "gte": "now-1h" } } }
      ]
    }
  },
  "aggs": {
    "by_service": {
      "terms": { "field": "service", "size": 50 },
      "aggs": {
        "error_types": { "terms": { "field": "error.type", "size": 10 } },
        "over_time": { "date_histogram": { "field": "@timestamp", "fixed_interval": "5m" } }
      }
    }
  }
}

Benzer pattern'da http.duration_ms üzerinde percentiles aggregation ile p50/p90/p95/p99 latency dashboard'u oluşturabilirsiniz.


Senaryo 3: APM — Application Performance Monitoring

Problem Tanımı

Distributed microservice mimarisi: 50 servis, her request birden fazla servisten geçiyor. Yavaşlığın hangi servisten kaynaklandığını bulmak, hata oranlarını izlemek ve bottleneck'leri tespit etmek gerekiyor.

Mimari

Mikroservisler (50) + Elastic APM Java Agent
         │ (HTTP — trace data)
    APM Server (x2, HA)
         │
    Data Nodes (x3, hot) + Master (x3) + Kibana APM UI (x1)

Node Yapısı — 9 Node

NodeRolSayıSpec
MasterDedicated master34 CPU, 8GB RAM
DataHot + APM data316 CPU, 64GB RAM, 1TB NVMe
APM ServerTrace collection24 CPU, 8GB RAM
KibanaAPM UI14 CPU, 8GB RAM

Java Agent Entegrasyonu

1. Agent ekleme (JVM argument):

java -javaagent:/opt/elastic-apm-agent.jar \
     -Delastic.apm.service_name=order-service \
     -Delastic.apm.server_urls=http://apm-server:8200 \
     -Delastic.apm.environment=production \
     -Delastic.apm.secret_token=${APM_SECRET_TOKEN} \
     -Delastic.apm.application_packages=com.mycompany \
     -jar order-service.jar

2. Spring Boot application.yml:

elastic:
  apm:
    service_name: order-service
    server_urls: http://apm-server:8200
    environment: production
    secret_token: ${APM_SECRET_TOKEN}
    application_packages: com.mycompany
    capture_body: transactions
    transaction_sample_rate: 0.5
    span_stack_trace_min_duration: 5ms

3. Custom Span'ler:

import co.elastic.apm.api.ElasticApm;
import co.elastic.apm.api.Span;
import co.elastic.apm.api.Transaction;

@Service
public class OrderService {

    private final ProductClient productClient;
    private final PaymentClient paymentClient;
    private final InventoryClient inventoryClient;

    public Order createOrder(OrderRequest request) {
        // Transaction otomatik yakalanır (Spring MVC)
        Transaction transaction = ElasticApm.currentTransaction();
        transaction.setLabel("user_id", request.getUserId());
        transaction.setLabel("item_count", request.getItems().size());

        // Stok kontrolü — custom span
        Span stockCheck = transaction.startSpan("app", "inventory", "check");
        stockCheck.setName("Stock Check");
        try {
            inventoryClient.checkStock(request.getItems());
        } catch (Exception e) {
            stockCheck.captureException(e);
            throw e;
        } finally {
            stockCheck.end();
        }

        // Ödeme — custom span
        Span payment = transaction.startSpan("app", "payment", "process");
        payment.setName("Payment Processing");
        try {
            paymentClient.charge(request.getPaymentInfo());
        } finally {
            payment.end();
        }

        // Sipariş kaydet
        Order order = saveOrder(request);
        transaction.setResult("success");
        return order;
    }
}

4. Annotation ile Span: Daha basit senaryolarda @CaptureSpan("calculate-recommendations") annotation'ı ile method'ları otomatik span olarak izleyebilirsiniz — sıfır boilerplate kod.

APM Verileri İçin Elasticsearch Query'leri

// Servis bazlı ortalama response time, p99 ve error rate
GET apm-*-transaction-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "range": { "@timestamp": { "gte": "now-1h" } } }
      ]
    }
  },
  "aggs": {
    "services": {
      "terms": { "field": "service.name", "size": 50 },
      "aggs": {
        "avg_duration": {
          "avg": { "field": "transaction.duration.us" }
        },
        "p99_duration": {
          "percentiles": {
            "field": "transaction.duration.us",
            "percents": [99]
          }
        },
        "error_rate": {
          "filter": { "term": { "event.outcome": "failure" } }
        }
      }
    }
  }
}

Senaryo 4: SIEM — Güvenlik Olayları ve Anomali Tespiti

Problem Tanımı

Bir finans şirketi: firewall, IDS/IPS, authentication, VPN logları — günlük 50GB güvenlik verisi. Anomali tespiti, real-time alerting, tehdit avı (threat hunting) ve compliance raporlama gerekiyor.

Mimari

Veri Kaynakları: Firewall, IDS/IPS, AD/LDAP, VPN/Proxy
         │
    Elastic Agent / Filebeat + Fleet Server
         │
    Logstash (GeoIP, Threat Intel lookup, ECS normalization)
         │
  ┌──────┼──────────────────┐
  HOT (x3)    WARM (x3)    COLD (x2)
  NVMe         SSD          HDD
  7 gün        30 gün       365 gün
  └──────┴──────────────────┘
  + Master (x3) + ML Node (x2) + Kibana SIEM (x2)

Node Yapısı — 15 Node

NodeRolSayıSpec
MasterDedicated master34 CPU, 8GB RAM
HotData_hot, Ingest316 CPU, 64GB RAM, 2TB NVMe
WarmData_warm38 CPU, 64GB RAM, 8TB SSD
ColdData_cold24 CPU, 32GB RAM, 32TB HDD
MLMachine learning216 CPU, 64GB RAM
KibanaSIEM UI + Alerting28 CPU, 16GB RAM

Güvenlik Olayları Mapping (ECS Format)

ECS (Elastic Common Schema) formatını kullanarak farklı kaynaklardan gelen verileri normalize ediyoruz:

PUT _index_template/security_events
{
  "index_patterns": ["security-events-*"],
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "siem_policy"
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "event": {
          "properties": {
            "category": { "type": "keyword" },
            "action": { "type": "keyword" },
            "outcome": { "type": "keyword" },
            "severity": { "type": "integer" },
            "risk_score": { "type": "float" }
          }
        },
        "source": {
          "properties": {
            "ip": { "type": "ip" },
            "port": { "type": "integer" },
            "geo": {
              "properties": {
                "country_name": { "type": "keyword" },
                "location": { "type": "geo_point" }
              }
            }
          }
        },
        "destination": {
          "properties": {
            "ip": { "type": "ip" },
            "port": { "type": "integer" }
          }
        },
        "user": {
          "properties": {
            "name": { "type": "keyword" },
            "domain": { "type": "keyword" }
          }
        },
        "threat": {
          "properties": {
            "tactic": { "type": "keyword" },
            "technique": { "type": "keyword" }
          }
        }
      }
    }
  }
}

Anomali Tespiti — ML Job

// Brute force login tespiti — IP başına anormal login failure sayısı
PUT _ml/anomaly_detectors/login_anomaly
{
  "description": "Unusual login failure rate detection",
  "analysis_config": {
    "bucket_span": "15m",
    "detectors": [
      {
        "function": "high_count",
        "by_field_name": "source.ip",
        "partition_field_name": "user.name"
      }
    ],
    "influencers": ["source.ip", "user.name", "source.geo.country_name"]
  },
  "data_description": { "time_field": "@timestamp" }
}

// Datafeed — sadece failed auth event'leri
PUT _ml/datafeeds/datafeed-login_anomaly
{
  "job_id": "login_anomaly",
  "indices": ["security-events-*"],
  "query": {
    "bool": {
      "filter": [
        { "term": { "event.category": "authentication" } },
        { "term": { "event.outcome": "failure" } }
      ]
    }
  }
}

// Başlat
POST _ml/anomaly_detectors/login_anomaly/_open
POST _ml/datafeeds/datafeed-login_anomaly/_start

SIEM Query'leri

// Brute force tespiti — 5 dakikada 10+ başarısız login
GET security-events-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "term": { "event.category": "authentication" } },
        { "term": { "event.outcome": "failure" } },
        { "range": { "@timestamp": { "gte": "now-5m" } } }
      ]
    }
  },
  "aggs": {
    "by_source_ip": {
      "terms": { "field": "source.ip", "min_doc_count": 10, "size": 100 },
      "aggs": {
        "target_users": {
          "terms": { "field": "user.name", "size": 20 }
        },
        "countries": {
          "terms": { "field": "source.geo.country_name" }
        }
      }
    }
  }
}

// Lateral movement tespiti — kısa sürede çok sunucuya erişen kullanıcılar
GET security-events-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "term": { "event.category": "authentication" } },
        { "term": { "event.outcome": "success" } },
        { "range": { "@timestamp": { "gte": "now-1h" } } }
      ]
    }
  },
  "aggs": {
    "by_user": {
      "terms": { "field": "user.name", "size": 100 },
      "aggs": {
        "unique_destinations": {
          "cardinality": { "field": "destination.ip" }
        },
        "many_destinations": {
          "bucket_selector": {
            "buckets_path": { "unique_dest": "unique_destinations" },
            "script": "params.unique_dest > 15"
          }
        }
      }
    }
  }
}

Alerting — Watcher Rule

Watcher ile brute force tespitini otomatik alarm'a çevirebilirsiniz:

PUT _watcher/watch/brute_force_alert
{
  "trigger": { "schedule": { "interval": "5m" } },
  "input": {
    "search": {
      "request": {
        "indices": ["security-events-*"],
        "body": {
          "size": 0,
          "query": {
            "bool": {
              "filter": [
                { "term": { "event.outcome": "failure" } },
                { "range": { "@timestamp": { "gte": "now-5m" } } }
              ]
            }
          },
          "aggs": {
            "attackers": { "terms": { "field": "source.ip", "min_doc_count": 10 } }
          }
        }
      }
    }
  },
  "condition": {
    "compare": { "ctx.payload.aggregations.attackers.buckets": { "not_eq": [] } }
  },
  "actions": {
    "notify_security": {
      "webhook": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/xxx/yyy/zzz",
        "body": "🚨 Brute Force Alert! {{#ctx.payload.aggregations.attackers.buckets}}{{key}} ({{doc_count}}x) {{/ctx.payload.aggregations.attackers.buckets}}"
      }
    }
  }
}

Senaryo Karşılaştırması

ÖzellikE-CommerceLog AnalyticsAPMSIEM
Veri5M doc, ~5GB100GB/gün20GB/gün50GB/gün
SaklamaSüresiz90 gün30 gün365 gün
Node914915
TierHotHot-Warm-ColdHot-WarmHot-Warm-Cold
Latency< 100ms< 5s< 2s< 10s

Özet

  1. E-Commerce Arama: Multi-field mapping ile autocomplete + faceted search. Coordinating node'lar arama load'unu dağıtır. Spring Boot + Elasticsearch Java Client ile tam entegrasyon. Edge-ngram tokenizer ile anlık öneri.

  2. Log Analytics (ELK): Hot-Warm-Cold mimarisi ile günlük 100GB veriyi verimli yönetin. ILM policy ile otomatik rollover, shrink, force merge. Logstash pipeline'ları ile veri enrichment ve normalization.

  3. APM: Elastic APM Java Agent ile sıfır kod değişikliği veya @CaptureSpan ile özel span'ler. Distributed tracing sayesinde request'in hangi serviste yavaşladığı anında görülür.

  4. SIEM: ECS formatında güvenlik olayları, ML anomaly detection ile brute force ve lateral movement tespiti. Watcher ile real-time alerting. Compliance için 365 gün saklama, cold tier ile maliyet optimizasyonu.

  5. Ortak patern: Dedicated master (3+), uygun shard boyutu (10-50GB), ILM ile yaşam döngüsü yönetimi ve mapping'i önceden tasarlamak — her senaryoda geçerli temel kurallardır.