Elasticsearch хранит документы в инвертированном индексе и умеет одновременно искать по тексту и считать агрегаты. Для логов это удобно: одна система отвечает и на вопрос «что случилось в 03:12», и на вопрос «сколько ошибок было у каждого сервиса за сутки». Ниже — установка, шаблон индекса, приём документов, запросы, ILM и диагностика.

Когда нужен свой кластер

Небольшой объём логов можно хранить в файлах и разбирать утилитами командной строки. Elasticsearch оправдан, когда нужен полнотекстовый поиск, агрегаты по полям, общий интерфейс для команды и хранение за несколько недель. Он требователен к памяти и диску, поэтому на одном сервере с базой данных его размещают с осторожностью.

  • поиск по сообщению, имени хоста, уровню и идентификатору запроса;
  • агрегаты по времени, сервисам и кодам ответа;
  • единые правила хранения и удаления старых индексов.

Для кластера из одного узла подходит режим single-node. Он упрощает запуск, но не даёт отказоустойчивости: при потере диска данные придётся восстанавливать из снимка.

Установка и базовая защита

Пакет из репозитория Elastic создаёт службу, каталоги /etc/elasticsearch и /var/lib/elasticsearch. Безопасность включена по умолчанию: TLS, пароль elastic и сертификат для клиентов. Не отключайте её ради удобства.

sudo systemctl status elasticsearch
sudo journalctl -u elasticsearch -n 80 --no-pager
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic
curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic https://localhost:9200

Для одноузлового стенда в elasticsearch.yml задают discovery.type: single-node, а размер кучи — в отдельном файле jvm.options.d/heap.options. Правило простое: не больше половины памяти сервера, а для больших объёмов учитывайте порог сжатых указателей.

Шаблон индекса и сопоставления

Типы полей важнее самого анализатора. Время должно быть date, адрес — ip, уровень и имя сервиса — keyword, а сообщение — text с отдельным подполем keyword для точных агрегатов. Если положить всё как text, группировка станет дорогой.

PUT _index_template/logs-app
{
  "index_patterns": ["logs-app-*"],
  "data_stream": {},
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 0,
      "refresh_interval": "5s",
      "index.lifecycle.name": "logs-app-policy"
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "message": { "type": "text" },
        "service": { "type": "keyword" },
        "log.level": { "type": "keyword" },
        "host.name": { "type": "keyword" },
        "host.ip": { "type": "ip" }
      }
    }
  }
}

Шаблон с data_stream создаёт поток logs-app-default и сам управляет скрытыми индексами. Запись идёт через _bulk или агент доставки.

Приём документов

В продакшене логи отправляет Filebeat, Fluent Bit или Logstash. Они читают файлы, добавляют метаданные и буферизуют отправку при недоступности кластера. Для проверки формата удобно отправить несколько документов вручную.

POST logs-app-default/_bulk
{"create":{}}
{"@timestamp":"2026-11-06T10:15:00Z","message":"timeout while calling billing","service":"api","log":{"level":"error"},"host":{"name":"web-01","ip":"10.0.0.5"}}
{"create":{}}
{"@timestamp":"2026-11-06T10:16:00Z","message":"request completed","service":"api","log":{"level":"info"},"host":{"name":"web-01","ip":"10.0.0.5"}}

Слишком крупный _bulk создаёт нагрузку и дольше повторяется при ошибке. Начните с нескольких мегабайт и настройте backoff в агенте.

Поиск и агрегаты

Запрос ниже ищет ошибки за сутки и одновременно строит две группировки: по часам и по сервисам. size: 0 отключает возврат самих документов, потому что нужны только счётчики. Фильтры в bool.filter не влияют на оценку релевантности и кэшируются эффективнее.

GET logs-app-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "range": { "@timestamp": { "gte": "now-24h" } } },
        { "term": { "log.level": "error" } }
      ]
    }
  },
  "aggs": {
    "per_hour": { "date_histogram": { "field": "@timestamp", "fixed_interval": "1h" } },
    "top_services": { "terms": { "field": "service", "size": 10 } }
  }
}

Для текста используют match, для точного значения — term. Шаблон *error* плохо масштабируется: лучше добавить отдельное поле.

Жизненный цикл данных

Политика ILM переводит старые данные в менее дорогие фазы и удаляет их по сроку. Для одного узла фаза warm может быть условной, но rollover и delete нужны обязательно, иначе диск закончится внезапно.

PUT _ilm/policy/logs-app-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": { "max_primary_shard_size": "30gb", "max_age": "7d" },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": { "forcemerge": { "max_num_segments": 1 }, "set_priority": { "priority": 50 } }
      },
      "delete": { "min_age": "30d", "actions": { "delete": {} } }
    }
  }
}

Срок хранения выбирайте по политике организации. Если в логах есть персональные данные, ограничьте доступ и срок хранения. Политику создают до первого индекса.

Снимки и восстановление

Снимки делают в отдельный каталог, подключённый через path.repo. Хранить их на том же диске, что и индексы, бессмысленно: при отказе диска пропадёт и копия. Репозиторий регистрируют один раз, затем создают снимок по расписанию.

PUT _snapshot/backup
{ "type": "fs", "settings": { "location": "/mnt/backup/elasticsearch", "compress": true } }
PUT _snapshot/backup/snap-2026-11-06?wait_for_completion=true
GET _snapshot/backup/_all

Восстановление проверяют на отдельном кластере. Перед крупным обновлением читайте матрицу совместимости и делайте копию заранее.

Диагностика

Здоровье кластера, нераспределённые шарды и заполнение диска — три главных индикатора. Жёлтый статус означает, что реплики не размещены, красный — что недоступны первичные шарды. Причина чаще всего в watermark, нехватке места или ошибке выделения памяти.

curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://localhost:9200/_cluster/health?pretty"
curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://localhost:9200/_cat/shards?v&s=state"
curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://localhost:9200/_cat/indices?v&s=store.size:desc"
curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://localhost:9200/_nodes/stats/fs,jvm?pretty"

При отказах пула потоков проверяют число одновременных запросов и размер кучи. Помогает снижение числа шардов и ограничение тяжёлых агрегатов.

Чек-лист эксплуатации

  • Порт 9200 не опубликован в интернет, доступ только через защищённую сеть.
  • Включены TLS, пароли и отдельные роли для приложений.
  • Настроены шаблон, ILM и ротация индексов.
  • Снимки лежат на другом носителе и проверены восстановлением.
  • Контролируются диск, heap, отказы пулов и статус кластера.
  • Срок хранения логов соответствует политике организации.

Итог

Elasticsearch превращает разрозненные логи в управляемый источник данных, но требует дисциплины в сопоставлениях, хранении и безопасности. Начните с одного узла, одного шаблона и одной политики ILM, проверьте приём и поиск на реальных событиях, затем добавляйте агенты и панели. Такой порядок не даёт кластеру разрастись раньше, чем появится понимание нагрузки.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте