Mert Özen Her Satırda Daha İleri
Veritabanı Elasticsearch ile Arama — #12

Elasticsearch'ü Production'da İşletmek: Güvenlik, Kapasite, İzleme ve Sık Görülen Sorunlar

Mert Özen 14 Kas 2026 13 dk 10 görüntülenme
Elasticsearch'ü Production'da İşletmek: Güvenlik, Kapasite, İzleme ve Sık Görülen Sorunlar

Elasticsearch'ü production'da işletmek; ağı kapatmak, TLS, uygulama başına alias'a verilmiş API key, en az üç master-eligible node, heap ve disk eşiklerini izlemek ve ölçülmüş bir yedekten dönme planı demek. Gerçek çıktılarla: self-signed CA'ya .NET client'tan parmak iziyle bağlanmak, DLS/FLS'in basic lisansta 403 vermesi, flood-stage watermark'ın yazmaları durdurması, circuit breaker hatası, slow log'daki arama metni, SLM ve restore ile SQL Server'dan yeniden index'lemenin süresi.

Sürüm notu: Bu yazıdaki örnekler Elasticsearch 9.5.6 (basic lisans), .NET 10 ve Elastic.Clients.Elasticsearch 9.5.3 ile, 2. yazıda kurduğumuz tek node'lu lab'da ve HTTPS denemesi için ayrı bir tek node'lu container'da çalıştırılmıştır. Üç node'lu cluster, Elastic Cloud ve Amazon OpenSearch Service çalıştırılmadı; onlarla ilgili bilgiler Elastic'in ve Amazon'un dokümanlarından.

Önce Tahmin Et

Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) için kurduğumuz arama, production'a çıkmadan önce bir istekle karşılaştı: Gül'ün müşteri hizmetleri ekranı yalnız Türkçe kitapları ve yalnız ISBN (kitabın uluslararası standart numarası), başlık ve fiyatı görsün. Elasticsearch bunu rolün içinde yapabiliyor: document level security (DLS; hangi document'ların görüneceğini bir sorguyla sınırlamak) ve field level security (FLS; hangi alanların görüneceğini sınırlamak). Lab'da bu kısıtlarla bir API key oluşturduk:

POST /_security/api_key
{
  "name": "bookstore-dls-test",
  "expiration": "1h",
  "role_descriptors": {
    "tr-books-only": {
      "indices": [
        {
          "names": ["books"],
          "privileges": ["read"],
          "query": { "term": { "language": "tr" } },
          "field_security": { "grant": ["isbn", "title", "price"] }
        }
      ]
    }
  }
}

Key oluşturulur mu? Oluşturulursa bu key'le yapılan bir arama "Dune" için ne döndürür: Türkçe Dune'u üç alanıyla mı, hiçbir şey mi, yoksa bir hata mı?

Ağ ve TLS

Production'ın ilk kuralı ağ: Elasticsearch'ün 9200 portu internete açık olmamalı. 2. yazıdaki compose.yaml portu yalnız 127.0.0.1'e bağlıyor; production'da da cluster yalnız uygulama sunucularının erişebildiği bir ağda durur. Elasticsearch 8.0'dan beri security varsayılan olarak açık; ama security'si kapatılmış ve internete açık bırakılmış cluster'lar geçmişte pek çok veri sızıntısına yol açtı ve bu hata hâlâ yapılıyor.

İkinci kural TLS (Transport Layer Security; istemci ile sunucu arasındaki trafiği şifreleyen protokol). Lab'da HTTP katmanında TLS'i kapatmıştık (xpack.security.http.ssl.enabled=false); bu, API key'lerin ağda açık metin gitmesi demek. Elasticsearch'ün resmî image'ı ise ayarlara dokunmadan ilk açılışta kendi CA'sını (Certificate Authority; sertifikaları imzalayan otorite) üretiyor ve hem HTTP'yi hem node'lar arası trafiği TLS'e alıyor. Bunu ikinci bir container'da denedim:

docker run -d --name bookstore-es-tls -p 127.0.0.1:9201:9200 -m 1500m `
  -e discovery.type=single-node -e ELASTIC_PASSWORD=<password> -e ES_JAVA_OPTS="-Xms512m -Xmx512m" `
  docker.elastic.co/elasticsearch/elasticsearch:9.5.6
docker cp bookstore-es-tls:/usr/share/elasticsearch/config/certs/http_ca.crt .

curl.exe -sS https://localhost:9201
curl: (60) SSL certificate problem: self signed certificate in certificate chain

Sunucunun sertifikası bu CA tarafından imzalanmış ve CA hiçbir işletim sisteminin güvendiği listede yok. İstemcinin bu sertifikaya güvenmesinin iki yolu var: CA'yı makinenin güven listesine eklemek ya da client'a CA'nın parmak izini (fingerprint) vermek. Client için ikincisi daha dar: yalnız bu CA'ya güveniyorsun. ElasticsearchOptions'a bir alan ekledik:

// 12. yazı: cluster self-signed bir CA kullanıyorsa HTTP CA sertifikasının SHA-256 parmak izi.
public string? CertificateFingerprint { get; set; }
if (!string.IsNullOrWhiteSpace(options.CertificateFingerprint))
{
    // Doğrulamayı kapatmak yerine tam olarak bu CA'ya güvenir.
    settings.CertificateFingerprint(options.CertificateFingerprint);
}

Parmak izini Windows'ta openssl kurmadan almak için lab'a küçük bir komut ekledik (X509Certificate2.GetCertHashString(HashAlgorithmName.SHA256)), bir de tek istek atan tls-check:

dotnet run --project src/Bookstore.SearchLab -- ca-fingerprint http_ca.crt
Subject: CN=Elasticsearch security auto-configuration HTTP CA
SHA-256: <fingerprint>

$env:BOOKSTORE_ES_URL = "https://localhost:9201"
dotnet run --project src/Bookstore.SearchLab -- tls-check
https://localhost:9201: failed, HttpRequestException: The SSL connection could not be established, see inner exception. The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot

$env:BOOKSTORE_ES_CA_FINGERPRINT = "<fingerprint>"
dotnet run --project src/Bookstore.SearchLab -- tls-check
https://localhost:9201: HTTP 404, books exists: False

404 doğru cevap: bu boş bir cluster, books yok; önemli olan bağlantının kurulması. Aynı adrese http:// ile gidince The response ended prematurely alınıyor; TLS bekleyen bir porta düz HTTP konuşulamıyor. Parmak izi .NET'in ürettiği büyük harfli, iki nokta üst üstesiz hâliyle de, openssl'in iki noktalı hâliyle de kabul edildi. Bu yöntem self-signed CA için; şirketin kendi CA'sı ya da herkese açık bir CA ile imzalanmış sertifikada (Elastic Cloud böyle) parmak izine gerek kalmıyor. Sertifika süreleri ve yenileme (SSL, TLS'in önceki adı; bugün ikisi aynı anlamda kullanılıyor), SSL/TLS Certificate'ları ve HTTPS serisinin konusu. Debug sırasında akla gelen CertificateValidations.AllowAll, 10. yazıdaki Testcontainers testinde atılacak bir container için kabul edilebilir; gerçek bir cluster'da TLS'in faydasını sıfırlar.

Rol ve API Key'ler: Okuyan Ayrı, Yazan Ayrı

Tahminin cevabı: key oluşturuluyor, arama düşüyor.

{
  "error": {
    "type": "security_exception",
    "reason": "current license is non-compliant for [field and document level security]",
    "license.expired.feature": "field and document level security",
    "indices_with_dls_or_fls": ["books-v2", "books"]
  },
  "status": 403
}

Lab'ın lisansı basic (GET /_license → "type": "basic"); DLS ve FLS ücretli aboneliklerde var. Hata key oluşturulurken değil ilk aramada geliyor; bunu deploy'dan önce bir testle yakalamazsan production'da 403 olarak öğrenirsin. Basic lisansla aynı ihtiyaç için iki yol var: Gül'ün ekranı için ayrı bir index (ya da alias'a filter eklenmiş ayrı bir alias), veya alanları ve kitapları API katmanında süzmek. Filtreli alias bir güvenlik sınırı değil: aynı key alttaki index'e de erişebiliyorsa filtre aşılır.

Basic lisansta olan ise index seviyesinde rol. 2. yazıdan beri API ve worker aynı key'i kullanıyordu: books*'ta okuma, yazma ve index oluşturma. Production'da ikisini ayırdık ve yetkiyi alias'a verdik:

POST /_security/api_key
{
  "name": "bookstore-api-prod",
  "expiration": "90d",
  "role_descriptors": {
    "bookstore-search-read": {
      "cluster": [],
      "indices": [ { "names": ["books"], "privileges": ["read", "view_index_metadata"] } ]
    }
  }
}

POST /_security/api_key
{
  "name": "bookstore-search-sync-prod",
  "expiration": "90d",
  "role_descriptors": {
    "bookstore-search-write": {
      "cluster": [],
      "indices": [ { "names": ["books"], "privileges": ["write"] } ]
    }
  }
}
GET /books/_count                     (bookstore-api-prod)
{"count":20036, ...}

GET /books-v2/_count                  (bookstore-api-prod)
action [indices:data/read/search] is unauthorized for API key id [<id>] of user [elastic] on indices [books-v2], this action is granted by the index privileges [read,all]

POST /books/_doc                      (bookstore-api-prod)
action [indices:data/write/index] is unauthorized for API key id [<id>] of user [elastic] on indices [books], this action is granted by the index privileges [create_doc,create,index,write,all]

GET /books/_count                     (bookstore-search-sync-prod)
action [indices:data/read/search] is unauthorized for API key id [<id>] of user [elastic] on indices [books], ...

API'yi okuma key'iyle çalıştırdım; /books/{isbn}, /books/search ve /books/suggest 200 döndü. Worker'ı yazma key'iyle çalıştırıp bir stok değişikliği yaptım: Synced 1 changes (1 indexed, ...). Yetki alias adına verildiği için 11. yazıdaki gibi bir geçişte key'ler değişmiyor; alias books-v3'e döndüğünde API aynı key'le çalışmaya devam etti. Okuma key'i ele geçirilse bile index'e yazamaz, alias'ın arkasındaki eski index'leri okuyamaz ve yeni bir index açamaz. Bu key'leri lab'da elastic kullanıcısıyla oluşturduk; production'da elastic yalnız ilk kurulumda kullanılır, sonrasında key'leri manage_api_key yetkisi olan bir yönetici rolü üretir. Sırların nerede saklanacağı ve nasıl dönüşümlü değiştirileceği, Configuration ve Secret Management serisinin konusu.

Kapasite: Heap, Bellek ve Node Rolleri

GET /_cat/nodes?v&h=name,node.role,heap.max,heap.percent
name         node.role   heap.max heap.percent
bookstore-es cdfhilmrstw    512mb           63

Lab node'u bütün rolleri tek başına taşıyor (cdfhilmrstw: master, data, ingest, machine learning ve diğerleri) ve heap'i 512 MB; compose.yaml'da -Xms512m -Xmx512m verdik. Elastic'in JVM (Java Virtual Machine; Elasticsearch'ün üzerinde çalıştığı Java çalışma ortamı) ayarları dokümanına göre production'da en iyisi heap'i Elasticsearch'ün kendisine bırakmak: node'un rollerine ve container'ın belleğine göre boyutu kendisi seçiyor. Elle verirsen Xms ve Xmx eşit olmalı, toplam belleğin yarısını geçmemeli ve sıkıştırılmış object pointer sınırının altında kalmalı (doküman 26 GB'ın çoğu sistemde güvenli olduğunu söylüyor). Belleğin diğer yarısı boşta değil: Lucene, index dosyalarını işletim sisteminin dosya cache'i üzerinden okuyor ve aramaların hızı büyük ölçüde o cache'e bağlı. Container'da "toplam bellek" container'ın limiti; limitsiz bir container'da Elasticsearch bütün makineyi görür.

Tek node production değil. Bir node'luk cluster'da o node durduğunda arama durur ve replica'lar atanamadığı için (2. yazıdaki yellow) diskteki her bozulma veri kaybıdır. Elastic'in dayanıklılık önerisi en az üç master-eligible node: cluster'ın durumuna karar verirken çoğunluk gerekiyor ve üç node'dan biri gidince kalan ikisi çoğunluğu koruyor; iki node'lu bir cluster bunu yapamıyor. Büyük cluster'larda master rolü ayrı ve küçük node'lara, veri ayrı node'lara veriliyor. Lab'da bir seferde en fazla iki container çalıştırdığım için üç node'lu kurulumu denemedim.

Disk Watermark'ları

GET /_cluster/settings?include_defaults=true&filter_path=defaults.cluster.routing.allocation.disk.watermark*
{"defaults":{"cluster":{"routing":{"allocation":{"disk":{"watermark":{"low":"85%","high":"90%","flood_stage":"95%",
 "low.max_headroom":"200GB","high.max_headroom":"150GB","flood_stage.max_headroom":"100GB", ...}}}}}}}

Disk %85 dolunca Elasticsearch o node'a yeni shard yerleştirmiyor, %90'da shard'ları başka node'lara taşımaya çalışıyor, %95'te ise o node'da shard'ı olan her index'e read_only_allow_delete bloğu koyuyor. max_headroom değerleri büyük disklerde yüzdeyi sınırlıyor: 10 TB'lık bir diskte %95 eşiği 500 GB boşluk demek, headroom bunu 100 GB'a indiriyor. Son eşiğin uygulamada neye benzediğini görmek için lab'da eşikleri %5, %6 ve %7'ye indirdim (lab diskinin doluluğu bunların üstünde) ve worker çalışırken bir kitabın stoğunu değiştirdim:

fail: Bookstore.SearchSync.SearchSyncWorker[0]
      Sync batch failed; retrying from RowVer 0x0000000000005671
      System.InvalidOperationException: Item 9781000000221 failed: 429 cluster_block_exception index [books-v3] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block; ...]

GET /_health_report/disk
{"indicators":{"disk":{"status":"red","symptom":"8 indices are not allowed to be updated. 1 node is out of disk or running low on disk space."}}}

Aramalar çalışmaya devam ediyor, yazmalar 429 ile reddediliyor. Worker 5. yazıdaki tasarım sayesinde checkpoint'i ilerletmedi ve her poll'da tekrar denedi. Eşikleri varsayılana döndürdükten sonra blok kendiliğinden kalktı (disk kullanımı high eşiğinin altına inince Elasticsearch kaldırıyor) ve bir sonraki denemede Synced 1 changes ... up to RowVer 0x0000000000005672 geldi. Production'da bu bir alarm konusu: %85'i geçtiğinde haber almalısın, %95'i beklememelisin. 11. yazıdaki geçiş sırasında iki index'in birlikte durduğunu da hesaba kat.

Circuit Breaker'lar ve Zaman Aşımı

GET /_nodes/stats/breaker
"request":   {"limit_size":"307.1mb", "estimated_size":"0b",   "tripped":0}
"fielddata": {"limit_size":"204.7mb", "estimated_size":"368b", "tripped":0}
"parent":    {"limit_size":"486.3mb", "estimated_size":"327mb", "tripped":0}

Circuit breaker'lar, bir isteğin heap'i doldurup node'u OutOfMemoryError ile düşürmesini önlüyor: bir istek ne kadar bellek kullanacağını tahmin ediyor ve sınırı aşacaksa çalışmadan reddediliyor. 512 MB heap'te request breaker 307,1 MB (%60), fielddata 204,7 MB (%40), parent 486,3 MB (%95, gerçek bellek kullanımına göre). Hatanın nasıl göründüğünü görmek için request breaker'ı geçici olarak 1 MB'a indirdim ve API'ye bir arama gönderdim:

fail: Bookstore.Api.BookSearchEndpoints[0]
      Elasticsearch search failed: HTTP 429 search_phase_execution_exception all shards failed
      ... CircuitBreakingException: [request] Data too large, data for [query] would be [1186436/1.1mb], which is larger than the limit of [1048576/1mb]

API 503 döndü; 10. yazıdaki karar burada işe yarıyor: 429'u kullanıcı isteğinde tekrar denemiyoruz. Gerçek bir cluster'da bu hatayı en sık 9. yazıdaki gibi çok büyük terms aggregation'lar, derin sayfalama (6. yazıdaki 10.000 sınırı bu yüzden var) ve text alanda açılmış fielddata üretiyor. Breaker'ı yükseltmek çözüm değil; isteği küçült. API tarafında 10. yazıda client'a verdiğimiz 5 saniyelik RequestTimeout bağlantıyı kesiyor ama Elasticsearch'teki işi durdurmuyor. Aramanın kendisini sınırlamak için isteğe timeout verilebiliyor; dokümana göre süre dolunca Elasticsearch o ana kadar topladığı sonuçları "timed_out": true ile döndürüyor. Lab'ın küçük index'inde bunu 1 nanosaniyelik bir timeout'la bile tetikleyemedim ("timed_out": false); kısa sorgular zaman aşımı kontrol noktalarına gelmeden bitiyor.

İzleme: Health Report, _cat API'leri ve Slow Log

GET /_health_report?filter_path=status,indicators.*.status
{"status":"green","indicators":{"master_is_stable":{"status":"green"},"repository_integrity":{"status":"green"},
 "disk":{"status":"green"},"shards_capacity":{"status":"green"},"shards_availability":{"status":"green"},
 "ilm":{"status":"green"},"slm":{"status":"green"}, ...}}

_health_report, _cluster/health'in yalnız renk veren cevabından daha fazlasını söylüyor: hangi göstergenin neden kırmızı olduğunu, neyi etkilediğini ve ne yapılacağını. Yukarıdaki disk denemesinde "8 index güncellenemiyor" diyen buydu. Bir alarm sistemine bağlanacak ilk uç nokta bu; ardından _cat/nodes (heap, disk), _cat/indices (boyut, sağlık) ve _cat/shards (atanmamış shard). 2. yazıdaki _cluster/allocation/explain, bir shard'ın neden atanmadığını tek tek anlatıyor.

Yavaş sorgular için slow log var. Eşiği geçici olarak 0'a çekip API'den bir arama yaptım:

PUT /books/_settings
{ "index.search.slowlog.threshold.query.warn": "0ms", "index.search.slowlog.include.user": true }
{
  "log.level": "WARN",
  "apikey.name": "bookstore-api-prod",
  "elasticsearch.slowlog.message": "[books-v2][0]",
  "elasticsearch.slowlog.source": "{\"from\":0,\"size\":1,\"query\":{\"bool\":{\"must\":[{\"function_score\":{\"query\":{\"bool\":{\"should\":[{\"multi_match\":{\"query\":\"kurk mantolu\", ...",
  "elasticsearch.slowlog.took": "14.2ms",
  "elasticsearch.slowlog.total_hits": "2 hits",
  "event.dataset": "elasticsearch.index_search_slowlog"
}

Eşik her index için ayrı ve shard seviyesinde ölçülüyor; production'da makul bir başlangıç warn için birkaç yüz milisaniye ya da birkaç saniye. include.user sayesinde yavaş sorgunun hangi key'den geldiği görünüyor; ayrı key'lerin bir faydası da bu. Dikkat: slow log, kullanıcının arama metnini ("kurk mantolu") olduğu gibi yazıyor. Logların nerede tutulduğu ve kimlerin okuyabildiği bir kişisel veri konusu. Bu ayarı denemeden sonra null vererek kaldırdım. Metric'leri ve logları merkezi bir sistemde toplamak Observability serisinin konusu.

Yedek: SLM ve Yeniden Index'lemenin Süresi

11. yazıda snapshot'ı elle aldık. Production'da bunu SLM (Snapshot Lifecycle Management; snapshot'ları zamanlayan ve eskilerini silen özellik) yapıyor; lab'daki basic lisansta çalıştı:

PUT /_slm/policy/nightly-books
{
  "schedule": "0 30 1 * * ?",
  "name": "<books-{now/d}>",
  "repository": "lab-backups",
  "config": { "indices": ["books-v*"], "include_global_state": false, "feature_states": ["synonyms"] },
  "retention": { "expire_after": "30d", "min_count": 5, "max_count": 50 }
}

POST /_slm/policy/nightly-books/_execute
{"snapshot_name":"books-2026.11.14-<suffix>"}

GET /_cat/snapshots/lab-backups?v&h=id,status,indices,duration
id                         status indices duration
books-2026.11.14           SUCCESS       2    201ms
books-2026.11.14-<suffix>  SUCCESS       2       0s

İkinci snapshot 0 saniye sürdü çünkü snapshot'lar artımlı: segment'lerin çoğu ilk snapshot'ta zaten vardı. schedule cron ifadesi: her gece 01:30.

Peki "veri zaten SQL Server'da, gerekirse yeniden index'leriz" yeterli mi? İkisini ölçtüm. Snapshot'tan books-v2'yi yeni bir adla geri yüklemek:

POST /_snapshot/lab-backups/books-2026.11.14-<suffix>/_restore?wait_for_completion=true
{ "indices": "books-v2", "rename_pattern": "books-(.+)", "rename_replacement": "restored-books-$1", "include_aliases": false }

GET /_cat/recovery/restored-books-v2?v&h=index,type,stage,time,files_total,bytes_total
index             type     stage time  files_total bytes_total
restored-books-v2 snapshot done  163ms 11          5.5mb

SQL Server'dan sıfırdan: boş bir books-v3 açtım, alias'ı ona çevirdim, worker'ın checkpoint'ini sıfırladım ve kitap sayısı 20.036 olana kadar geçen süreyi ölçtüm:

UPDATE dbo.SearchSyncState SET LastRowVer = 0x0000000000000000 WHERE Name = 'books';
info: Bookstore.SearchSync.SearchSyncWorker[0]
      Synced 1000 changes (1000 indexed, 0 deleted, 0 already up to date) up to RowVer 0x0000000000005642
info: Bookstore.SearchSync.SearchSyncWorker[0]
      Synced 36 changes (36 indexed, 0 deleted, 0 already up to date) up to RowVer 0x000000000000566C

Worker 21 batch yazdı ve _count 5,3 saniyede 20.036'ya ulaştı (worker'ın açılışı dahil; süreyi worker'ı başlatan script'te _count'u yarım saniyede bir sorgulayarak ölçtüm). Restore ise 0,16 saniye sürdü (5,5 MB'lık dosya kopyası). Lab'da ikisi de kısa; önemli olan nasıl büyüdükleri. Restore, index'in byte boyutuyla ve repository'nin hızıyla büyüyor; yeniden index'leme ise kitap sayısıyla, SQL Server'daki sorguyla, analiz zincirinin maliyetiyle ve Elasticsearch'ün indexleme hızıyla. Bu oranla bir milyon kitap dakikalar, yüz milyon document saatler sürer ve bu süre boyunca arama ya eksik sonuç verir ya da 11. yazıdaki gibi ayrı bir index'te beklenir. Kendi verinle iki süreyi ölçüp felaket kurtarma hedefinle karşılaştır; ölçmeden "yeniden index'leriz" bir plan değil. İki yol birbirinin yerine de geçmiyor: snapshot, SQL Server'daki checkpoint'in gerisinde kalan bir anın kopyası; restore'dan sonra worker'ı snapshot anındaki RowVer'den tekrar oynatmak gerekiyor (11. yazıdaki external version'lar bunu güvenli yapıyor).

Üretimde Dikkat

Managed mı self-managed mı? Elastic Cloud (Elastic'in kendi servisi) cluster'ı, sürüm güncellemelerini, snapshot'ları ve TLS'i yönetiyor; ücretli abonelik özellikleri de (DLS/FLS gibi) planına göre geliyor. Amazon OpenSearch Service ise Elasticsearch değil OpenSearch çalıştırıyor; farkları 13. yazıda. Self-managed kurulumda bu yazıdaki her başlık (ağ, TLS, roller, heap, disk, izleme, yedek, güncelleme) senin işin; makine maliyetinin yanında bu işçiliği de hesapla. Bu yazıda managed servislerin hiçbirini çalıştırmadım.

Sürüm güncellemesini planla. Major sürüm atlanmıyor: 8.x'ten 9.x'e geçmeden önce son 8.x sürümüne (bugün 8.19) geçilir ve deprecation uyarıları temizlenir. Ayrıntılar ve kaldırılanlar 13. yazıda.

Production'a çıkmadan önce bir liste: 9200 internete kapalı; HTTP ve node'lar arası TLS açık; uygulama başına, süreli ve alias'a verilmiş API key'ler; en az üç master-eligible node ve replica en az 1; heap Elasticsearch'e bırakılmış ya da belleğin yarısının altında; disk %85 alarmı; _health_report izleniyor; slow log eşikleri ayarlı ve logların erişimi kısıtlı; SLM çalışıyor ve bir restore denenmiş; client'ta debug modu kapalı (10. yazı).

Sık Düşülen Tuzaklar

Tek node'u production saymak. Node durunca arama durur, replica yoktur, her disk sorunu veri kaybıdır.

Test için AllowAll sertifika doğrulamasını production'da bırakmak. Self-signed CA için parmak izi ver, mümkünse güvenilen bir CA kullan.

Ücretli bir özelliği basic lisansta varsaymak. DLS ve FLS rolü oluşturulurken değil, ilk aramada 403 veriyor.

API ve worker'ın aynı geniş key'i paylaşması. Okuyan key yazamamalı, yazan key okuyamamalı; ikisi de alias'a verilmeli, books*'a değil.

Disk dolana kadar beklemek. Flood stage'de yazmalar durur; alarm low eşiğinde çalmalı.

Yedek olarak yalnız "SQL Server'dan yeniden index'leriz" demek ve süresini hiç ölçmemek.

Slow log'u kişisel veri olarak görmemek. Arama metni loglara açık yazılıyor.

Küçük Bir Deneme

★☆☆ Lab'da bookstore-api-prod key'ini DELETE /_security/api_key ile geçersiz kıl ve API'ye bir arama gönder. Log'da hangi HTTP durumu ve hata tipi var? API kullanıcıya ne döndürüyor?

★★☆ Okuma key'ine yalnız Türkçe kitapları gösteren filtreli bir alias (books-tr, "filter": { "term": { "language": "tr" } }) üzerinden yetki ver. Bu key ile books'u okumak mümkün mü? DLS'ten farkı ne?

★★★ Restore ile yeniden index'leme süresini 200.000 kitapla tekrar ölç (seed-sql 200000, 1. yazıdaki veri). Hangisi doğrusal büyüyor? Restore'dan sonra worker'ı snapshot anındaki RowVer'den tekrar oynatan adımları yaz.

Serinin son yazısında sürümlere bakıyoruz: Elasticsearch 8'den 9'a geçerken kaldırılanlar ve değişenler, 9.1'den 9.5'e gelen yenilikler, OpenSearch 3'ün nerede ayrıştığı ve hangisinin seçileceği.