Elasticsearch ILM ile Index Yaşam Döngüsü Yönetimi

Elasticsearch kümelerinde zaman içinde biriken veri miktarı düşündüğünüzden çok daha hızlı büyür. Log verileri, metrikler, uygulama olayları… Bunların hepsi disk alanını doldurur, sorgu performansını düşürür ve operasyonel maliyetleri artırır. İşte tam bu noktada Index Lifecycle Management (ILM), yani Index Yaşam Döngüsü Yönetimi devreye girer. ILM, Elasticsearch’ün indekslerinizi otomatik olarak yönetmesini sağlayan güçlü bir mekanizmadır ve doğru yapılandırıldığında hem performansı artırır hem de maliyetleri dramatik biçimde düşürür.

Bu yazıda gerçek dünya senaryolarıyla ILM’yi baştan sona ele alacağız. Bir log yönetim sistemi kuruyorsunuz diyelim, günlük yüzlerce GB veri geliyor. Bu veriyi nasıl yönetirsiniz? Hangi indeksler hızlı SSD’de durmalı, hangilerini soğuk depolamaya taşımalısınız, hangilerini silmelisiniz? Tüm bu soruların yanıtını ILM ile otomatize edebilirsiniz.

ILM Nedir ve Neden Kullanmalısınız

ILM, Elasticsearch 6.6 sürümüyle hayatımıza girdi ve 7.x ile birlikte olgunlaştı. Temel fikir şu: bir indeks oluşturulduğu andan itibaren silindiği ana kadar belirli aşamalardan geçer. Bu aşamaları siz tanımlarsınız, Elasticsearch otomatik olarak yönetir.

Düşünün ki bir e-ticaret şirketinde çalışıyorsunuz. Uygulama loglarınız var. Son 24 saatin logları aktif olarak sorgulanıyor, bu yüzden bunların hızlı diskde olması gerekiyor. Geçen haftanın loglarına ara sıra bakılıyor. Geçen ayın logları sadece uyumluluk gereklilikleri için tutuluyor. 6 aydan eski loglar ise tamamen silinebilir. İşte ILM tam olarak bunu yapıyor.

ILM kullanmadan bu yönetimi elle yapmaya çalışırsanız ya sürekli script yazacaksınız ya da bir gün diske yer kalmadığı için sistemin çöktüğünü göreceksiniz. Her ikisi de yaşanmış senaryolar.

ILM Aşamaları

ILM dört temel aşamadan oluşur:

  • Hot (Sıcak): İndeks aktif olarak yazılıyor ve sorgulanıyor. En yüksek performans gereksinimi bu aşamada.
  • Warm (Ilık): Yazma işlemi bitti ama hala sık sık sorgulanıyor. Biraz daha yavaş depolama kullanılabilir.
  • Cold (Soğuk): Nadiren sorgulanıyor. Daha ucuz, daha yavaş depolama. Searchable snapshot burada devreye girebilir.
  • Delete (Sil): Artık ihtiyaç yok, indeks siliniyor.

Her aşamada çeşitli aksiyonlar gerçekleştirebilirsiniz. Rollover, shrink, force merge, freeze, snapshot, delete gibi işlemler bunların başında geliyor.

İlk ILM Policy’sini Oluşturmak

Hemen pratik bir örnekle başlayalım. Uygulama logları için basit bir policy oluşturalım.

curl -X PUT "localhost:9200/_ilm/policy/uygulama-log-policy" 
  -H 'Content-Type: application/json' 
  -d '{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "50gb",
            "max_age": "1d",
            "max_docs": 10000000
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "freeze": {},
          "set_priority": {
            "priority": 0
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}'

Bu policy şunu yapıyor: İndeks 50GB’a ulaşırsa veya 1 gün geçerse ya da 10 milyon döküman dolduğunda rollover yap. 7 gün sonra warm aşamasına geç ve tek sharda düşür. 30 gün sonra cold aşamasında freeze et. 90 gün sonra sil.

Index Template ile ILM’yi Birleştirmek

Policy’yi oluşturdunuz ama tek başına işe yaramaz. Bu policy’yi yeni oluşturulacak indekslere otomatik uygulamak için index template kullanmanız gerekiyor.

curl -X PUT "localhost:9200/_index_template/uygulama-log-template" 
  -H 'Content-Type: application/json' 
  -d '{
  "index_patterns": ["uygulama-log-*"],
  "template": {
    "settings": {
      "number_of_shards": 2,
      "number_of_replicas": 1,
      "index.lifecycle.name": "uygulama-log-policy",
      "index.lifecycle.rollover_alias": "uygulama-log"
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "level": {
          "type": "keyword"
        },
        "message": {
          "type": "text"
        },
        "service": {
          "type": "keyword"
        }
      }
    }
  }
}'

Şimdi ilk indeksi ve alias’ı oluşturalım. Bu adımı atlayanların başı dertte olur, unutmayın.

curl -X PUT "localhost:9200/uygulama-log-000001" 
  -H 'Content-Type: application/json' 
  -d '{
  "aliases": {
    "uygulama-log": {
      "is_write_index": true
    }
  }
}'

Artık verilerinizi uygulama-log alias’ına yazabilirsiniz. ILM rollover koşulları karşılandığında otomatik olarak uygulama-log-000002, uygulama-log-000003 gibi yeni indeksler oluşturulacak.

Data Streams ile Modern Yaklaşım

Elasticsearch 7.9 ve sonrasında data streams özelliği geldi ve ILM kullanımını çok daha kolaylaştırdı. Alias yönetimini ortadan kaldırdı ve zaman serisi verileri için daha temiz bir arayüz sundu.

curl -X PUT "localhost:9200/_index_template/logs-uygulama-template" 
  -H 'Content-Type: application/json' 
  -d '{
  "index_patterns": ["logs-uygulama-*"],
  "data_stream": {},
  "template": {
    "settings": {
      "index.lifecycle.name": "uygulama-log-policy"
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "log.level": {
          "type": "keyword"
        },
        "message": {
          "type": "text"
        }
      }
    }
  },
  "priority": 500
}'

Data stream oluşturmak için artık ayrıca ilk indeksi oluşturmanıza gerek yok. İlk veri yazıldığında otomatik oluşuyor.

curl -X POST "localhost:9200/logs-uygulama-default/_doc" 
  -H 'Content-Type: application/json' 
  -d '{
  "@timestamp": "2024-01-15T10:30:00.000Z",
  "log.level": "INFO",
  "message": "Servis basarıyla basladi",
  "service.name": "payment-api"
}'

ILM Durumunu İzlemek

Policy’yi kurdunuz, şimdi ne olduğunu nasıl takip edeceksiniz? ILM’nin durumunu kontrol etmek için birkaç faydalı komut var.

# Belirli bir indeksin ILM durumunu görmek
curl -X GET "localhost:9200/uygulama-log-000001/_ilm/explain?pretty"

# Tüm ILM yönetilen indekslerin durumunu görmek
curl -X GET "localhost:9200/*/_ilm/explain?only_managed=true&pretty"

# ILM politikasının kendisini görmek
curl -X GET "localhost:9200/_ilm/policy/uygulama-log-policy?pretty"

Explain komutunun çıktısında dikkat etmeniz gereken alanlar şunlar:

  • phase: Şu an hangi aşamada olduğu
  • action: Hangi aksiyonun çalıştığı
  • step: Aksiyonun hangi adımında olduğu
  • phase_time_millis: Bu aşamaya ne zaman geçildiği
  • failed_step: Eğer bir hata varsa hangi adımda başarısız olduğu

Gerçek Dünya Senaryosu: E-ticaret Log Yönetimi

Diyelim ki 50 sunuculu bir e-ticaret platformunu yönetiyorsunuz. Günlük yaklaşık 200GB log üretiyorsunuz. Farklı tipte loglarınız var: web access logları, uygulama logları, ödeme logları. Her birinin farklı saklama gereklilikleri var.

Ödeme logları yasal gereklilikler nedeniyle 5 yıl saklanmak zorunda. Web access logları 90 gün yeterli. Uygulama logları 30 gün.

Önce ödeme logları için özel bir policy oluşturalım:

curl -X PUT "localhost:9200/_ilm/policy/odeme-log-policy" 
  -H 'Content-Type: application/json' 
  -d '{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_primary_shard_size": "30gb",
            "max_age": "1d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "30d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "180d",
        "actions": {
          "searchable_snapshot": {
            "snapshot_repository": "odeme-arsiv-repo"
          }
        }
      },
      "delete": {
        "min_age": "1825d",
        "actions": {
          "wait_for_snapshot": {
            "policy": "gunluk-snapshot-policy"
          },
          "delete": {
            "delete_searchable_snapshot": false
          }
        }
      }
    }
  }
}'

Bu yapıda cold aşamasında searchable snapshot kullandık. Bu özellik sayesinde indeks daha ucuz nesne depolamaya (S3, GCS, Azure Blob) taşınıyor ama hala sorgulanabiliyor. Disk maliyetlerini dramatik biçimde düşürüyor.

ILM Hata Yönetimi ve Troubleshooting

ILM çalışırken bazen adımlar başarısız olabilir. En sık karşılaşılan durumlar:

Shrink işlemi sırasında node yeterli alan olmadığında hata alırsınız. Force merge sırasında disk dolabilir. Snapshot repository bağlantısı kopabilir.

Başarısız bir ILM adımını yeniden tetiklemek için:

# Hatalı adımı kontrol et
curl -X GET "localhost:9200/uygulama-log-000005/_ilm/explain?pretty"

# Adımı yeniden dene
curl -X POST "localhost:9200/uygulama-log-000005/_ilm/retry"

# ILM'yi geçici olarak durdur (bakım için)
curl -X POST "localhost:9200/_ilm/stop"

# ILM'yi yeniden başlat
curl -X POST "localhost:9200/_ilm/start"

# ILM'nin çalışıp çalışmadığını kontrol et
curl -X GET "localhost:9200/_ilm/status"

Bazen bir indeksi manuel olarak bir sonraki aşamaya geçirmeniz gerekebilir. Test ortamlarında ya da acil durumlarda bu işe yarıyor:

curl -X POST "localhost:9200/_ilm/move/uygulama-log-000005" 
  -H 'Content-Type: application/json' 
  -d '{
  "current_step": {
    "phase": "hot",
    "action": "rollover",
    "name": "check-rollover-ready"
  },
  "next_step": {
    "phase": "warm",
    "action": "shrink",
    "name": "shrink"
  }
}'

Mevcut İndekslere ILM Eklemek

Çoğu zaman yeni bir sistem kurmuyorsunuzdur, mevcut bir sisteme ILM eklemeniz gerekir. Bu biraz daha dikkat ister.

# Önce policy'yi oluştur
# Ardından mevcut indekse policy ekle
curl -X PUT "localhost:9200/eski-log-indeksi/_settings" 
  -H 'Content-Type: application/json' 
  -d '{
  "index": {
    "lifecycle": {
      "name": "uygulama-log-policy"
    }
  }
}'

# Eğer alias kullanıyorsanız rollover alias da ekleyin
curl -X PUT "localhost:9200/eski-log-indeksi/_settings" 
  -H 'Content-Type: application/json' 
  -d '{
  "index": {
    "lifecycle": {
      "name": "uygulama-log-policy",
      "rollover_alias": "uygulama-log"
    }
  }
}'

Dikkat: Mevcut indekslere ILM eklerken min_age hesabı indeksin oluşturulma tarihinden itibaren başlar. Çok eski bir indekse ILM eklediğinizde anında delete aşamasına geçmesin diye policy’nizi kontrol edin.

Küme Düzeyinde Konfigürasyon

ILM’nin ne sıklıkta çalışacağını ayarlayabilirsiniz. Varsayılan değer 10 dakikadır. Küçük test ortamlarında bunu düşürmek, büyük üretim ortamlarında ise artırmak mantıklı olabilir.

# ILM polling aralığını değiştir
curl -X PUT "localhost:9200/_cluster/settings" 
  -H 'Content-Type: application/json' 
  -d '{
  "persistent": {
    "indices.lifecycle.poll_interval": "5m"
  }
}'

Prod ortamda 1-2 dakikaya çekmeyin. Her polling döngüsünde tüm ILM yönetilen indeksler kontrol ediliyor. Binlerce indeksiniz varsa bu ciddi bir yük oluşturabilir. 10 dakika çoğu senaryo için yeterli.

Kibana ile ILM Yönetimi

Tüm bu işlemleri Kibana üzerinden de yapabilirsiniz. Stack Management > Index Lifecycle Policies bölümünden görsel arayüzle policy oluşturabilir ve yönetebilirsiniz.

Kibana arayüzü özellikle şu durumlarda çok işe yarıyor:

  • Policy’lerin genel durumuna bakış atmak için
  • Hangi indekslerin hangi aşamada olduğunu görmek için
  • ILM hatalarını hızlıca tespit etmek için

Ama prodüksiyon ortamında policy’lerinizi mutlaka kod olarak (IaC prensibiyle) yönetin. Kibana’dan tıklayarak yaptığınız değişiklikler versiyon kontrolünde olmayacak ve bir gün başınıza iş açacak.

İzleme ve Alerting

ILM’yi kurdunuz ama işiniz bitmedi. İzleme şart. Kibana’da basit bir Watcher kuralıyla ILM hatalarını izleyebilirsiniz.

curl -X PUT "localhost:9200/_watcher/watch/ilm-hata-izle" 
  -H 'Content-Type: application/json' 
  -d '{
  "trigger": {
    "schedule": {
      "interval": "30m"
    }
  },
  "input": {
    "search": {
      "request": {
        "indices": ["*"],
        "body": {
          "query": {
            "bool": {
              "must": [
                {"term": {"_ilm_step_info.type": "error"}}
              ]
            }
          }
        }
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.hits.total.value": {
        "gt": 0
      }
    }
  },
  "actions": {
    "slack-bildirim": {
      "webhook": {
        "scheme": "https",
        "host": "hooks.slack.com",
        "port": 443,
        "method": "post",
        "path": "/services/XXXX/YYYY/ZZZZ",
        "params": {},
        "headers": {
          "Content-Type": "application/json"
        },
        "body": "{"text": "ILM hata tespit edildi! Elasticsearch kumesini kontrol edin."}"
      }
    }
  }
}'

Bunun yanı sıra Prometheus + Elasticsearch Exporter kullanıyorsanız elasticsearch_indices_indexing_index_total ve elasticsearch_cluster_health_status metriklerini izlemeyi unutmayın.

Sık Yapılan Hatalar

Yıllarca Elasticsearch yöneten birinin gözlemlerine göre en sık yapılan hatalar şunlar:

  • Rollover alias olmadan policy uygulamak: Policy çalışıyor gibi görünür ama rollover hiç tetiklenmez.
  • min_age’i yanlış hesaplamak: Warm phase’e geçiş için min_age, indeksin oluşturulma tarihinden değil, hot phase’e girildiği andan itibaren hesaplanır. Bu önemli fark.
  • Shrink için yeterli node kontrolü yapmamak: Shrink işlemi için tüm shardların tek bir node’a taşınması gerekir. Node yeterince disk alanı yoksa işlem başarısız olur.
  • Tek shard olan indekse shrink uygulamak: Zaten tek shardınız varsa shrink aksiyonu hata verir ya da atlayacak diye umarken çakılır.
  • ILM polling interval’ını çok düşük ayarlamak: Küçük test ortamında işe yarar gibi görünür, prodda felaket olur.

Sonuç

ILM, Elasticsearch’teki en güçlü operasyonel özelliklerden biri. Doğru kurulduğunda hem disk maliyetlerinizi azaltır hem de kümenizin performansını artırır hem de operasyonel yükü dramatik biçimde düşürür. Artık her gece cron job’larla eski indeksleri silen scriptler yazmanıza gerek yok.

Önerdiğim yaklaşım şu: Önce basit bir policy ile başlayın. Hot ve delete aşaması yeterli. Sistemi izleyin, öğrenin. Ardından warm ve cold aşamalarını ekleyin. Searchable snapshot gibi ileri özellikleri ancak temel konfor seviyenize ulaştıktan sonra deneyin.

ILM’nin her ortamda aynı şekilde çalışmayacağını unutmayın. 10 node’luk bir küme ile 3 node’luk bir kümenin ihtiyaçları farklı. Veri hacminize, saklama gereksinimlerinize ve bütçenize göre policy’lerinizi şekillendirin. Ve her şeyden önemlisi, bu konfigürasyonları Git’e atın, versiyonlayın, dokümante edin. Bir yıl sonra o policy’yi neden öyle kurduğunuzu kendiniz bile hatırlamayabilirsiniz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir