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

rsyslog + Elasticsearch: 50 серверов, централизованные логи, поиск за секунды

Elasticsearch 0.16 вышел свежо, мы пробуем прогнать syslog через rsyslog с JSON-выводом прямо в индекс. Grep по tar-архивам больше не единственный вариант.

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

Elasticsearch 0.16 вышел в 2011, появляются первые попытки строить централизованный поиск по логам на базе Lucene-движка

Когда серверов двадцать - grep по syslog терпим. Когда их пятьдесят, и инцидент случился в четыре утра, а логи раскиданы по /var/log на каждой машине плюс часть архивирована в tar.gz с ротацией - начинается настоящее удовольствие. Разбираем, что случилось, час-полтора, потому что половину времени тратим не на анализ, а на то, чтобы вообще найти нужную строчку.

Задача, которую мы поставили себе в марте: централизовать логи и сделать по ним полнотекстовый поиск. Не просто syslog-коллектор с записью в файл на центральный сервер - это не сильно лучше исходной ситуации. Нужен именно поиск: по ключевому слову, по хосту, по временному диапазону, за минуты, а не за час.

Elasticsearch на этом фоне выглядел интересно. Версия 0.16, REST API, схема без жёсткой декларации - то есть можно слать JSON-документы с произвольными полями, и движок сам разберётся с маппингом. Для логов это удобно: не нужно заранее объявлять, какие поля будут в syslog-сообщении от каждого приложения.

Цепочка

Схема, которую мы собрали, выглядит так:

rsyslog на каждом хосте
  -> omfwd (UDP 514 или TCP) ->
    rsyslog-коллектор (один сервер)
      -> omelasticsearch (модуль) ->
        Elasticsearch (localhost)
          -> REST API / веб-интерфейс

rsyslog мы использовали уже везде - он стандартный в CentOS 6 и Debian 6. В нём появился модуль omelasticsearch, который умеет слать сообщения прямо в ES через HTTP. Это и есть ключевой кусок.

На центральном коллекторе конфиг rsyslog выглядит примерно так:

module(load="omelasticsearch")

template(name="es-json" type="list") {
    constant(value="{")
    constant(value="\"@timestamp\":\"")  property(name="timereported" dateFormat="rfc3339")
    constant(value="\",\"host\":\"")    property(name="hostname")
    constant(value="\",\"severity\":\"") property(name="syslogseverity-text")
    constant(value="\",\"facility\":\"") property(name="syslogfacility-text")
    constant(value="\",\"message\":\"")  property(name="msg" format="json")
    constant(value="\"}")
}

*.* action(
    type="omelasticsearch"
    server="localhost"
    serverport="9200"
    template="es-json"
    searchIndex="syslog-%$year%-%$month%"
    dynSearchIndex="on"
)

Индекс назван по месяцу (syslog-2011-04), чтобы старые данные можно было удалять без реиндексации. Это не архивный подход - просто разумная практика, когда объём неизвестен и диск не бесконечный.

Что работает хорошо

Поиск. REST API Elasticsearch принимает запросы в JSON, и даже простой curl с полнотекстовым запросом находит нужные строки по всем хостам за секунды. Найти все события с kernel: EXT3-fs error за последние трое суток - это один запрос с фильтром по @timestamp. Раньше это был цикл по пятидесяти хостам с ssh и grep, плюс разархивирование ротированных файлов там, где инцидент выходил за пределы текущего лога.

Поля из JSON. Если приложение пишет структурированные логи (у нас несколько самописных сервисов пишут JSON в syslog), Elasticsearch разбирает их автоматически и делает поля доступными для поиска. То есть можно искать не по подстроке, а по конкретному полю: user_id:12345 или status:500.

Нет агентов. rsyslog уже стоит на всех хостах, дополнительного процесса на каждой машине ставить не нужно. Только поправить конфиг и добавить пересылку на коллектор.

Что пока трудно

omelasticsearch в боевых условиях. Модуль новый. При перезапуске Elasticsearch или сети коллектор теряет сообщения - буферизации, которая бы пережидала недоступность ES и потом досылала, в текущей версии нет или она работает не так, как ожидаешь. Мы потеряли несколько минут логов при перезапуске ES для обновления конфига.

JSON-шаблоны - это ручная работа. Если в syslog-сообщении есть кавычки или обратный слеш, JSON ломается, и документ не индексируется. Флаг format="json" в rsyslog должен это эскейпить, но мы поймали несколько случаев, где оно вело себя не идеально. Скорее всего специфика конкретной версии модуля, но нервирует.

Elasticsearch и RAM. На выделенном сервере с 4 ГБ JVM ест половину с первых часов работы - это норма для Lucene, но сервер нужно выделять под это специально, не подселять.

Веб-интерфейс

Elasticsearch сам по себе - только API. Для просмотра логов через браузер мы прикрутили Kibana - это простой веб-фронтенд на JavaScript, который умеет строить запросы к ES и показывать результаты таблицей с пагинацией. Dashboards там пока очень простые, но искать по полям и временному диапазону удобно даже без настройки.

Где сейчас

Система работает на парке под управлением третью неделю. Инциденты, которые раньше разбирались час-полтора, теперь диагностируются в части «найти логи» за пять минут. Это ощутимо.

Остаётся вопрос надёжности пайплайна - потеря логов при недоступности ES неприятна, особенно если именно в этот момент что-то сломалось. Смотрим в сторону промежуточной очереди (в голове вертится идея про отдельный буферный файл на коллекторе как fallback), но это следующий шаг. Пока радуемся, что grep по пятидесяти хостам ушёл в прошлое.

Контакт

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

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