ADG Оставить заявку
Блог Данные и аналитика 4 мин чтения

EL-стек без Kibana: собираем логи nginx и Windows Event Log в Elasticsearch

Elasticsearch 0.19 + Logstash 1.0 для централизованных логов: конфиг, производительность на одном узле, и почему мы отложили Kibana в сторону.

Контекст момента

Elasticsearch 0.19 и Logstash 1.0 набирают популярность как open-source стек для централизованного хранения и поиска по логам

Три месяца назад мы переводили клиента на syslog-ng PE с Elasticsearch - там источники были Unix-only и объём скромный. Сейчас другая история: клиент из ритейла, смешанная среда - nginx на фронтах, десятки Windows-серверов с Event Log, и вопрос «что вообще происходит в инфраструктуре» решается раз в три дня grep-ом по SSH. Нас позвали сделать нормальный централизованный сбор.

Задача: один узел, все логи в одном месте, поиск через API или хотя бы curl. Не SIEM, не compliance, просто видимость.

Почему именно Elasticsearch + Logstash

Мы смотрели на несколько вариантов. Splunk - коммерческий, лицензия с ограничением по объёму данных в сутки, у клиента бюджет не резиновый. Graylog2 - интересный, но тащит за собой MongoDB и выглядит сыровато для продакшена. Syslog-ng PE с его elasticsearch destination мы уже знаем, но там нет нормального парсинга Windows Event Log из коробки.

Logstash 1.0.x в итоге оказался разумным выбором: он умеет принимать syslog, читать файлы, принимать события через TCP/UDP, разбирать их через grok-паттерны и писать прямо в Elasticsearch. Одна JVM на весь пайплайн. Elasticsearch 0.19 - уже достаточно стабильный для индексации логов, REST API работает предсказуемо.

Kibana. Она существует, мы смотрели на неё - но версия 1.x, которая есть сейчас, требует довольно много ручной настройки дашбордов, фактически это Kibana поверх Elasticsearch без нормального темплейтинга. Для разовой демонстрации подойдёт, для операционной работы - нет. Оставили на потом, пока работаем через прямые запросы к ES.

Схема сборки

nginx access.log  ──► Logstash (file input)   ─┐
nginx error.log   ──► Logstash (file input)   ─┤
                                                ├─► Elasticsearch 0.19
Windows Event Log ──► NXLog (UDP → Logstash)  ─┘
     (через nxlog-агент на каждом хосте)

На Windows-хостах поставили nxlog - он отправляет события в syslog-совместимом формате по UDP на Logstash. Logstash слушает на порту 514 и дополнительно читает файлы nginx.

Конфиг Logstash

input {
  file {
    path => "/var/log/nginx/access.log"
    type => "nginx_access"
  }
  file {
    path => "/var/log/nginx/error.log"
    type => "nginx_error"
  }
  syslog {
    port => 514
    type => "windows_event"
  }
}

filter {
  if [type] == "nginx_access" {
    grok {
      pattern => "%{COMBINEDAPACHELOG}"
    }
    date {
      match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
    }
  }
  if [type] == "windows_event" {
    grok {
      pattern => "%{SYSLOGTIMESTAMP:evtime} %{SYSLOGHOST:winhost} %{GREEDYDATA:message}"
    }
  }
}

output {
  elasticsearch {
    host => "localhost"
    port => 9200
    index => "logs-%{+YYYY.MM.dd}"
  }
}

Ничего хитрого. Дневные индексы (logs-2012.06.27) - так удобнее потом чистить старые данные простым удалением индекса, без шардинга внутри.

Производительность на одном узле

Машина - сервер с 8 ядрами, 16 ГБ RAM, SSD под ES-данные. JVM для Logstash настроили на -Xmx512m - больше давать не нужно, узкое место там не heap.

На пиковой нагрузке (утренний старт бизнеса + ночной batch-процесс одновременно) получаем около 50 тысяч событий в минуту суммарно. ES при этом съедает примерно 4-5 ГБ heap, индексация не проседает. Logstash CPU - 1-1,5 ядра на grok-парсинг.

Два момента, на которые наступили:

Первое - grok на Windows Event Log. Формат, который гонит nxlog, немного отличается от стандартного syslog, особенно в части EventID и уровня важности. Паттерн пришлось дописывать руками, стандартный %{SYSLOGLINE} не справился. Потратили полдня на отладку через http://grokdebug.herokuapp.com - очень рекомендуем, экономит время.

Второе - маппинг полей в ES. По умолчанию Elasticsearch сам угадывает тип поля при первой индексации. Если в первом событии response_code пришёл как строка, а дальше как число - индекс ломается с ошибкой mapping conflict. Мы заранее положили явный mapping через PUT на новый индекс перед первой записью. Не пожалели.

Что в итоге

Поиск по логам через curl работает: curl 'localhost:9200/logs-*/_search?q=status:500&pretty' даёт список 500-х за все дни мгновенно. Клиентские инженеры освоили базовые запросы за час.

Для сопровождения такой инфраструктуры важно сразу договориться о retention - мы настроили cron, который удаляет индексы старше 30 дней. Иначе диск закончится незаметно и в неподходящий момент.

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

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.