Главная » Хабрахабр » Мониторинг Elasticsearch без боли и страданий

Мониторинг Elasticsearch без боли и страданий

«А оно там делает магию»
кто-то из тех, кого я удалённо консультировал по Эластику.

Я всегда говорю, что верю в три вещи: мониторинг, логи и бэкапы.

Это не очень сложно (и не требует использования дополнительных плагинов и сторонних сервисов) — ибо REST API, предоставляемое самим Elasticsearch простое, понятное и удобное в использовании. Тема про то, как мы собираем и храним логи, достаточно полно была раскрыта в предыдущих статьях, тема про бэкапы в Elasticsearch — совсем отдельная история, поэтому в этой, возможно заключительной, статье цикла я расскажу как происходит мониторинг моего любимого кластера. Всего-то надо немного углубиться в его внутреннее устройство, понять, что означают все эти метрики, пулы тредов, веса распределения шардов по нодам, настройки очередей — и не останется никаких вопросов о том, что же за «магию» эластик делает прямо сейчас.

Критически важно в любой момент знать, в каком он состоянии, причём контроль обязательно должен быть многоуровневым. На недавней конференции Highload++ 2017 я рассказал о том, как строил кластер своей мечты, и говорил, что недостаточно просто построить сервис. Причём одна минута из двух уйдёт на подключение к корпоративному VPN и логин в Zabbix.
Разбудите меня посреди ночи (отделу мониторинга привет!) — и через две минуты я буду знать, в каком состоянии находится кластер.

Кластер разделён на «горячий» и «тёплый» сегменты (hot/warm cluster architecture). Disclaimer: Описываемая структура состоит из кластера Elasticsearch 5.x.x, с выделенными мастер-, дата- и клиентскими нодами. Но общие принципы мониторинга ES можно применить к кластеру почти любой конфигурации и версий. Скриншоты приведены по системе мониторинга Zabbix.

Итак, уровни мониторинга снизу вверх:
Нижний уровень мониторинга — железо и базовые метрики, такие же, какие собираются с любого сервера, но некоторые, в случае кластера Elasticsearch, требуют особого внимания. А именно:

  • Загрузка процессорных ядер и общее LA;
  • Использование памяти;
  • Пинг до сервера и время отклика;
  • i/o по дисковой подсистеме;
  • Остаток свободного места на дисках (настройка watermark.low по умолчанию запрещает эластику создавать новые индексы при наличии менее 85% свободного места );
  • Использование сети и, особенно, коллизии и ошибки на интерфейсах.

Я специально выделил ошибки сети — эластик крайне чувствителен к проблемам с сетью. По умолчанию текущий активный мастер пингует остальные ноды раз в секунду, а ноды, в свою очередь, проверяют наличие кворума мастер-нод. Если на каком-то этапе нода не ответила на пинг в течение 30 секунд, то она помечается как недоступная, с последствиями в виде ребаланса кластера и долгих проверок целостности. А это совсем не то, чем правильно спроектированный кластер должен быть занят посреди рабочего дня.
Уровень повыше, но мониторинг всё такой же стандартный:

  • Количество запущенных процессов сервиса elasticsearch;
  • Используемая сервисом память;
  • Пинг до порта приложения (стандартные порты elasticsearch/kibana — 9200/9300/5601).

Если любая из метрик упала в ноль — это, означает что приложение упало, либо зависло, и немедленно вызывается алерт по уровню disaster.
С этого момента начинается самое интересное. Поскольку Elasticsearch написан на java, то сервис запускается как обычное jvm-приложение и поначалу для его мониторинга я использовал агент Jolokia, ставший стандартом де-факто для мониторинга java-приложений в нашей компании.

Запускается вместе с приложением как javaagent, слушает порт, принимает http-запросы, возвращает JMX-метрики, обёртнутые в JSON, причём делает это быстро, в отличии от медленного JMX-агента того же Zabbix. Jolokia, как сказано на сайте разработчика, это «JMX на капсаицине», который, по сути, представляет собой JMX-HTTP гейт. Словом, прекрасный сервис для мониторинга java-приложений, оказавшийся в случае с Elasticsearch… совершенно бесполезным. Умеет в авторизацию, firewall-friendly, позволяет разграничение доступов до уровня отдельных mbeans.

Принимает http-запросы, возвращает JSON — что может быть лучше? Дело в том, что Elasticsearch предоставляет замечательное API, которое полностью покрывает все потребности в мониторинге — в том числе, те же метрики о состоянии java-машины, что и Jolokia.

Пройдёмся API более детально, от простого к сложному:

Уровень Кластера

_cluster/health

Общие метрики состояния кластера. Самые важные из них это:

  • status — принимает одно из значений: green/yellow/red. Тут всё понятно: green — всё хорошо; yellow — какие-то шарды отсутствуют/инициализируются, но оставшихся кластеру достаточно, чтобы собраться в консистентное состояние; red — всё плохо, каким-то индексам не хватает шардов до 100% целостности, беда, трагедия, будите админа (но новые данные кластер, тем не менее, принимает).
  • number_of_nodes/number_of_data_nodes — общее количество нод в кластере, количество дата-нод. Полезно мониторить их изменение, потому что иногда (крайне редко) случаются ситуации, когда какая-то из нод залипла под нагрузкой и вывалилась из кластера, но потребляет ресурсы и держит порт открытым. Такое поведение не отлавливается стандартным мониторингом сервисов (уровня ниже), но на целостность кластера влияет и ещё как.
  • relocating_shards — шарды, находящиеся в процессе ребаланса,  перемещаются с одной дата-ноды на другую.
  • initializing_shards — инициализирующися шарды. Метрика отличается от нуля только в моменты, когда создаются новые индексы и эластик распределяет их шарды по нодам. Ситуация вполне нормальная, но только если этот процесс не длится дольше некоторого времени. Время вычисляется эмпирическим путём, на моём кластере установлено в ±10 минут. Если дольше — что-то не то, алерт.
  • unassigned_shards — количество неназначенных шард. Значение метрики не равное нулю — это очень плохой признак. Либо из кластера выпала нода, либо не хватает места для размещения, либо какая-то другая причина и нужно незамедлительно разбираться.
  • number_of_pending_tasks — количество задач в очереди на исполнение. Если не равно нулю — теряем реалтайм, кластер не успевает.
  • task_max_waiting_in_queue_millis — среднее время ожидания задачи в очереди на исполнение (в мс.). Аналогично предыдущей метрике, должно быть нулевым. Ибо «нет ничего хуже, чем догонять и ждать».
  • active_shards_percent_as_number — количество  активных шардов в процентах. Активные шарды — все, кроме тех, что находятся в состоянии unassigned/initializing. В нормальном состоянии — 100%. Для удобства отображения на графиках я использую обратную метрику, вычисляемую как inactive_shards_percent_as_number = 100 — active_shards_percent_as_number.

На основании этих метрик строится вот такой, насыщенный информацией, график:

Здесь и далее по клику откроется покрупнее

Алармы по этим метрикам поднимаются если: В идеальном состоянии все его метрики должен лежать на нуле.

  • status = red — сразу, yellow — через 10 минут;
  • количество нод меньше зафиксированного количества;
  • количество шард в статусе initializing больше 0 дольше 10 минут;
  • количество шард в статусе unassigned не равно 0 — сразу.

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

_cluster/stats

Расширенная статистика по кластеру, из которой собираем только несколько метрик:

  • docs.count — количество проиндексированных записей в кластере по состоянию на текущий момент времени. Из этой метрики вычисляется количество новых записей в секунду по простой формуле: rps = (docs.count(t) — docs.count(t-1))/t. И если вдруг rps упал в ноль — аларм.
  • indices.count — мы используем Elasticsearch для хранения и оперативного доступа к  логам приложений. Каждый день для логов каждого приложения создаётся новый индекс, и каждый день индексы старше 21 дня удаляются из кластера. Таким образом каждый день создаётся и удаляется одинаковое количество индексов. Рост общего количества индексов значит, что либо админы поставили под сбор в эластик логи нового приложения, либо сломался скрипт очистки старых индексов. Не критично, но поглядывать нужно.
  • fs.free_in_bytes, fs.total_in_bytes, fs.available_in_bytes — информация о файловой системе, хранит данные о суммарном объёме места, доступного всему кластеру.

Уровень ноды

_nodes/stats

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

Метрики по памяти процесса elastic

jvm.mem.heap_max_in_bytes — выделенная память в байтах, jvm.mem.heap_used_in_bytes — используемая память в байтах, jvm.mem.heap_used_percent — используемая память, в процентах от выделенного Xmx.

Регулярно приходит Garbage Collector и очищает неиспользуемые пулы памяти. Очень важный параметр, и вот почему: Elasticsearch хранит в оперативной памяти каждой дата-ноды индексную часть каждого шарда принадлежащего этой ноде для осуществления поиска. Через некоторое время, если данных на ноде много и они перестают помещаться в память, сборщик выполняет очистку всё дольше и дольше, пытаясь найти то, что вообще можно очистить, вплоть до полного stop the world.

Есть еще одна причина следить за памятью — по моему опыту, после 4-5 часов в состоянии jvm.mem.heap_used_percent > 95% падение процесса становится неизбежным. А из-за того, что кластер Elasticsearch работает со скоростью самой медленной дата-ноды, залипать начинает уже весь кластер.

Горячая зона: График использования памяти в течение дня обычно выглядит как-то так и это совершенно нормальная картина.

Тёплая зона, тут картина выглядит более спокойной, хотя и менее сбалансированной:

  • fs.total.total_in_bytes, fs.total.free_in_bytes, fs.total.available_in_bytes — метрики по дисковому пространству, доступному каждой ноде. Если значение приближается к watermark.low — аларм.
  • http.current_open, http.total_opened — количество открытых http-подключений к нодам — на момент опроса и общее, накопительный счетчик с момента запуска ноды, из которого легко вычисляется rps.

Сведение значения метрик http.total_rps со всех нод в один график позволяет оценить адекватность балансировки нагрузки по нодам и видеть перекосы, как только они появляются. Как видим на графике ниже — они минимальны:

То, из какой секции её собирать, зависит от роли ноды. throttle_time_in_millis — очень интересная метрика, существующая в нескольких секциях на каждой ноде. Метрика показывает время ожидания выполнения операции в миллисекундах, в идеале не должно отличаться от нуля:

  • indexing.throttle_time_in_millis — время, которое кластер потратил на ожидание при индексации новых данных. Имеет смысл только на нодах, принимающих данные.
  • store.throttle_time_in_millis — время, затраченное кластером, на ожидание при записи новых данных на диск. Аналогично метрике выше — имеет смысл только на нодах куда поступают новые данные.
  • recovery.throttle_time_in_millis — включает в себя не только время ожидания при восстановлении шард (например, после сбоев), но и время ожидания при перемещении шард с ноды на ноду (например, при ребалансе или миграции шард между зонами hot/warm). Метрика особо актуальна на нодах, где данные хранятся долго.
  • merges.total_throttled_time_in_millis — общее время, затраченное кластером на ожидание объединения сегментов на данной ноде. Накопительный счётчик.

Каких-то конкретных диапазонов верхних значений в которые должны вписываться throttle_times не существует, это зависит от конкретной инсталляции и вычисляется эмпирическим путём. В идеале, конечно, должен быть ноль.

Имеет ненулевые значения только на нодах с данными. search — секция, содержащая метрики запросов выполняемых на ноде. Из десятка метрик в этой секции особо полезны две:

  • search.query_total — всего запросов на поиск, выполненных на ноде с момента её перезагрузки. Из этой метрики вычисляем среднее количество запросов в секунду.
  • search.query_time_in_millis — время в миллисекундах, затраченное на все операции поиска с момента перезагрузки ноды.

На основании этих двух метрик строится график среднего времени затраченного на выполнение одного поискового запроса на каждой дата-ноде кластера:

Так же видна резкая разница по скорости поиска между «горячей» (сервера с SSD) и «тёплой» зонами. Как видим — идеальный график ровный в течении дня, без резких всплесков.

Соответственно, результирующее время поиска будет примерно равно времени, затраченному на поиск на самой медленной ноде, плюс время на агрегацию найденных данных. Надо учесть, что при выполнении поиска Elasticsearch осуществляет его по всем нодам, где находятся шарды индекса (и primary, и replica). И если ваши пользователи вдруг начали жаловаться, что поиск стал медленным, анализ этого графика позволит найти ноду, из-за которой это происходит.

Очередей много, подробное описание их назначения — в официальной документации, но набор возвращаемых метрик для каждой очереди один и тот же: threads, queue, active, rejected, largest, completed. thread_pool — группа метрик, описывающих пулы очередей, куда попадают операции на выполнение. Основные очереди, которые обязательно должны попадать в мониторинг это — generic, bulk, refresh и search.

А вот на эти метрики, на мой взгляд, нужно обращать особое внимание:

  • thread_pool.bulk.completed — счётчик, хранящий количество выполненных операций пакетной (bulk) записи данных в кластер с момента перезагрузки ноды. Из него вычисляется rps по записи.
  • thread_pool.buk.active — количество задач в очереди на добавление данных на момент опроса, показывает загруженность кластера по записи на текущий момент времени. Если этот параметр выходит за установленный размер очереди, начинает расти следующий счётчик.
  • thread_pool.bulk.rejected — счётчик количества отказов по запросам на добавление данных. Имеет смысл только на нодах осуществляющих приём данных. Суммируется накопительным итогом, раздельно по нодам, обнуляется в момент полной перезагрузки ноды.

Рост этого показателя — очень плохой признак, который показывает, что эластику не хватает ресурсов для приёма новых данных. Бороться, без добавления железа в кластер, сложно. Можно, конечно, добавлять количество процессоров-обработчиков и увеличивать размеры bulk-очередей, но разработчики не рекомендуют этого делать. Правильное решение — наращивать мощность железа, добавлять в кластер новые ноды, дробить нагрузку. Второй неприятный момент в том, что сервис доставки данных до эластика должен уметь обрабатывать отказы и «дожимать» данные позже, чтобы избежать потери данных.

Нет смысла мониторить bulk-очереди на нодах, которые не работают на приём данных. Метрику по отказам нужно контролировать по каждой очереди, и привязывать к ней аларм, в зависимости от назначения ноды. Например, сравнивая нагруженность search-пула в разных зонах кластера, можно построить аналитику по разумному сроку хранения данных на горячих нодах, прежде чем осуществлять их перенос на медленные ноды для длительного хранения. Также, информация о загрузке пулов очень полезна для оптимизации работы кластера. Впрочем, аналитика и тонкая настройка кластера — это отдельная объёмная тема и, наверное, уже не для этой статьи.

Хорошо, с метриками более-менее разобрались, осталось рассмотреть последний вопрос — как их получать и отправлять в мониторинг. Использовать Zabbix или любой другой — не важно, принцип один и тот же.

Можно выполнять curl-запросы непосредственно в API, прямо до нужной метрики. Вариантов, как всегда, несколько. Можно делать запрос на весь API, получать большой JSON со всеми метриками и разбирать его. Плюсы — просто, минусы — медленно и нерационально. По сути это обертка над библиотекой urllib, который транслирует функции в те же запросы к Elasticsearch API и предоставляет к ним более удобный интерфейс. Когда-то я делал именно так, но потом перешёл на модуль elasticsearch в python. Шаблоны и скрины в Zabbix, предоставить, к сожалению не могу, по вполне понятным причинам. Исходный код скрипта и описание его работы можно традиционно посмотреть на GitHub.

Метрик в Elasticsearch API много (несколько сотен) и перечисление их всех выходит за рамки одной статьи, поэтому я описал только наиболее значимые из тех что мы собираем и то, на что необходимо обратить пристальное внимание при их мониторинге. Надеюсь, что после прочтения статьи у вас не осталось сомнений в том, что никакой «магии» эластик внутри себя не делает — только нормальную работу хорошего, надёжного сервиса. Своеобразного, не без тараканов, но тем не менее, прекрасного.

Если что-то осталось непонятным, возникли вопросы или некоторые места требуют более детального рассмотрения — пишите в комментарии, обсудим.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Подборка] Разработка, дизайн и продвижение сайтов: 17 полезных материалов

Создать качественный сайт, который привлечет пользователей продуманным интерфейсом и красивым дизайном – непростая задача, с которой не справляется огромное количество компаний. Я собрала полезные ссылки, которые помогут пройти этот путь и не совершить необязательные ошибки. Выбор: самостоятельная разработка, студии, фрилансеры ...

[Из песочницы] «Референтная модель BIAN» для банковской индустрии или как перестать изобретать велосипед

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