Я уже довольно давно и успешно использую Logstash + Elasticsearch с визуализацией данных в Kibana (общепринятое сокращение для этой тройки - ELK) для сбора, хранения и обработки логов, но для обретения счастья с этой связкой мне потребовалось несколько итераций.

Поскольку в мире СПО все постоянно развивается и становится лучше, сразу хочу отметить, что все описанное актуально для Logstash версиий 1.4-1.5 и Elasticsearch версий 1.4 - 1.7 при нагрузке в ~20kk сообщений в день.

Итак, передо мной стояла задача собирать логи из разных источников, обрабатывать их, и хранить в удобном для обработки виде, с продвинутым веб-интерфейсом. Ранее я уже использовал для схожей задачи Graylog2, который тоже использует Elasticsearch для хранения логов, минусы этого решения я знал, поэтому было решено попробовать использовать второго большого игрока на этом поприще - ELK.

Первый вариант использования Logstash и Elasticsearch был очень наивным:

источники логов -> Logstash -> Elasticsearch

То есть Logstash принимает логи в различных форматах по сети, обрабатывает их, и напрямую кладет в Elasticsearch.

Практически сразу была выявлена проблема - при нагрузке на Elasticsearch (например, кто-то решил через Kibana получить из логов самые популярные файлы на нашем CDN за пару недель) Logstash затыкался, кушал CPU и переставал принимать новые сообщения. Связано это поведение с тем, что Logstash написан на JRuby и на данный момент имеет один общий Loop обработки, так что при таймауте на операции записи в Elasticsearch этот Loop ломался. При этом со стороны процесс Logstash выглядел вполне живым, слушал все нужные порты, потреблял ресурсы системы, и определить поломку можно было только с помощью скрипта мониторинга, проверяющего свежесть данных в Elasticsearch.

На этом же этапе была выявлена еще одна особенность Elasticsearch. Дело в том, что он весьма прожорлив до оперативки, поскольку вынужден хранить индексы для все активных данных в памяти. Более того, поскольку JVM мы запускаем с определенными ограничениями по потребляемой памяти (-Xmx NN), Elasticsearch легко может накушаться памяти до внутреннего OOM Java, и грустно издохнуть. При этом Logstash тоже ожидаемо залипает и перестает принимать сообщения. Для ограничения жора памяти на сложных запросах в Elasticsearch есть специальный механизм Circuit Breaker, который пытается угадать тебуемое количество памяти до выполнения запроса, и прервать его выполнение пре превышении определенных границ. По моему опыту суровая правда заключается в том, что не надо пытаться запихнуть в ELK больше данных, чем ваш сервер может переварить. То есть Circuit Breaker можно тюнить вполне успешно, тогда Elastiсsearch на интересные большие запросы просто откажется отвечать, но хотя-бы не упадет.

Вообще у Elasticsearch весьма хорошая документация по ограничению использования оперативной памяти, и она мне очень пригодилась, и даже до добавления в сервера оперативки удалось добиться того, чтобы Elasticsearch не падал с OOM, но главная проблема с затыкающимся Logstash так и осталась.

Для решения этой проблемы я выбрал простую и достаточно популярную схему с буферизацией входящих логов в Redis. Таким образом, схема работы стала выглядеть так:

источники логов -> Logstash-front -> Redis -> Logstash-back -> Elasticsearch

Таким образом, Redis выступает в роли эластичного буфера, сглаживая пики нагрузки, и храня сообщения при перезапусках или падения Logstash-back и Elasticsearch. При это Logstash-front сделан максимально тупым, и не выполняет никакой обработки сообщений - он просто кладет их в Redis.

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

А еще хочется отметить очень значительный прогресс в разработке ELK, за пол-года активного использования:

  • производительность Logstash в новых релизах выросла процентов на 20;
  • используемое место на диске сократилось вдвое (Logstash стал использовать более разумный маппинг для данных по-умолчанию);
  • потребление оперативной памяти Elasticsearch уменьшилось на треть;
  • скорость восстановления кластера Elasticsearch выросла на порядок.

Comments

comments powered by Disqus