Новые возможности мониторинга Java приложений в Zabbix 3.4

в 10:12, , рубрики: java, jboss, jmx, monitoring, open source, opensource, zabbix, zabbix 3.4, Блог компании Zabbix, Серверное администрирование, системное администрирование

Что случилось?

Вышел долгожданный релиз Zabbix 3.4, который принёс много полезных улучшений, среди которых оказались настраиваемые JMX endpoints и гибкое обнаружение MBean’ов.

Это так круто, да?

Если вы используете Zabbix и вам требуется мониторить Java приложения, то да — это может сильно облегчить вам жизнь, потому что раньше приходилось прибегать к различным ухищрениям, а теперь всё работает, как говорится, “из коробки”.

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 1

А что не так с этими JMX endpoints?

Нативный мониторинг Java приложений через JMX появился в Zabbix давно — начиная с версии 2.0 — и с тех пор этот функционал улучшается от версии к версии. Но так вышло, что в предыдущих релизах JMX endpoint был жёстко зашит в код Zabbix Java Gateway совершенно наивным образом.
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 2
Как выяснилось, в мире Java существует масса софта, который использует иные endpoints, а старые версии Zabbix не позволяли менять этот параметр. Для многих пользователей это стало реальной проблемой. Например, популярный сервер приложений JBoss EAP 6 использует для удалённого доступа к JMX свой протокол JBoss Remoting вместо RMI и JMXServiceURL для него должен выглядеть так:

service:jmx:remoting-jmx://{HOST.CONN}:{HOST.PORT}

А, например, WebSphere 8.5 использует RMI поверх IIOP (а не JRMP) и для него JMXServiceURL должен быть таким:

service:jmx:iiop://{HOST.CONN}:{HOST.PORT}/jndi/JMXConnector

Zabbix 3.4 как раз решает эту проблему.

Я ничего не понял. JMX, RMI, JNDI? WTF?

Хорошо-хорошо, давайте немного разберёмся, как всё это работает.
JMX (Java Management Extensions) — технология Java, предназначенная для мониторинга и управления (в т.ч. удалённо) различными объектами (ресурсами): приложениями, устройствами, сетями — лишь бы этот объект был написан на Java.

Эти ресурсы называются MBeans (ManagedBeans). Каждый такой объект реализует определённый интерфейс, через который можно получить доступ к значениям атрибутов этого объекта, а также вызвать его методы и получать уведомления (если приложение зарегистрирует соответствующие “слушающие” MBean’ы).

MBeans регистрируются на MBean Server — реестре объектов. Любой зарегистрированный объект становится доступным для приложений (точнее, становится доступным его интерфейс).
Доступ к ресурсам осуществляется при помощи JMX-коннекторов, которые делают MBean Server доступным для JMX-клиентов. JMX-коннектор состоит из клиента и сервера. Коннектор-сервер соединяется с MBean-сервером и слушает запросы соединений от клиентов. Коннектор-клиент обычно находится на другой JVM, а чаще всего вообще на другой машине по отношению к коннектор-серверу.

JMX API имеет стандартный протокол подключения, основанный на Remote Method Invocation (RMI). Этот протокол позволяет JMX-клиенту удалённо получить доступ к MBean’ам на MBean-сервере. Кроме штатного RMI существуют и другие протоколы: JMXMP, JBoss Remoting, Hessian, Burlap, и даже HTTP и SNMP.

Используя интерфейс MBean’а клиент может получать различные метрики этого объекта, а также вызывать публичные методы.

Схематично взаимодействие компонентов можно изобразить так:

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 3

Любое приложение на платформе Java SE “из коробки” имеет возможности для его мониторинга: RMI коннектор автоматически делает доступным ваше Java приложение для удалённого управления и мониторинга. Достаточно лишь запустить приложение с нужными параметрами, и JMX-клиенты (а Zabbix Java Gateway — это JMX-клиент) уже смогут подключаться к нему удалённо и получать нужные метрики.

Чтобы указать JMX-клиенту конкретное приложение, к которому вы хотите подключиться, используется специальный адрес, который называется JMX endpoint (он же JMXServiceURL). Если говорить строже, то это адрес коннектор-сервера JMX API. Формат этого адреса определяется RFC 2609 и RFC 3111. В общем случае он выглядит так:

service:jmx:protocol:sap

Где "service:jmx:" — константа.
protocol — это транспортный протокол (один из многих: RMI, JMXMP, etc), используемый для подключения к коннектор-серверу.
sap — адрес, по которому коннектор-сервер может быть найден. Задаётся в таком формате (это подмножество синтаксиса, определённого в RFC 2609):

//[host[:port]][url-path]

host[:port] — ipv4 адрес хоста (или ipv6, заключённый в квадратные скобки) и необязательный (в зависимости от протокола) номер порта.
url-path — необязательный URL (обязательность зависит от протокола).

Лучше всего разобраться с этим на примере. Часто можно встретить такой JMX endpoint, вид которого некоторых может ввести в ступор:

service:jmx:rmi://host:port1/jndi/rmi://host:port2/jmxrmi

Но на самом деле не всё так страшно.
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 4
host — это целевой хост, где запущено наше приложение.
port1 — это порт RMI-сервера, к которому мы хотим подключиться.
а port2 — это порт RMI registry (каталог, где регистрируются RMI-серверы). По умолчанию: 1099.

Если знать о том, что RMI-реестр выдаёт адрес и порт RMI-сервера по запросу клиента, то становится понятно, что первая часть здесь лишняя. Таким образом адрес можно сократить до такого вида:
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 5
url-path часть означает буквально следующее: возьми ту часть URL, которая следует сразу за /jndi/ и выполни по этому адресу JNDI-запрос в RMI registry, чтобы получить информацию об RMI-сервере. Реестр вернёт в ответ его хост и порт.
Следует отметить, что порт в таком случае генерируется случайным образом и могут возникнуть проблемы с настройкой файрвола. В таких случаях и используют предыдущий вариант записи JMX endpoint’а, потому что он позволяет явно указать порт.

Если вам хотелось бы глубже разобраться в JMX, то рекомендуем обратиться к официальной документации Oracle.

Может лучше на практике?

Нет ничего проще :) Давайте для примера попробуем настроить мониторинг JBoss EAP 6.4.

Для начала сделаем несколько предположений:

  1. Вы уже установили Zabbix 3.4 и Zabbix Java Gateway. Если еще нет, то вы можете сделать это в соответствии с документацией Zabbix.
  2. Zabbix Server и Java Gateway с префиксом /usr/local/.
  3. JBoss уже установлен в /opt/jboss-eap-6.4/ и запускается в standalone режиме.
  4. Для простоты эксперимента будем считать, что все эти компоненты работают на одной и той же машине.
  5. Firewall и SELinux отключены (или настроены соответствующим образом, но это выходит за рамки статьи).

Сделаем несколько простых настроек в zabbix_server.conf:

JavaGateway=127.0.0.1
StartJavaPollers=5

И в конфиге zabbix_java/settings.sh (или zabbix_java_gateway.conf):

START_POLLERS=5

Проверьте, что JBoss слушает свой стандартный management port:

$ netstat -natp | grep 9999
tcp        0      0 127.0.0.1:9999          0.0.0.0:*               LISTEN      10148/java

Теперь давайте создадим в Zabbix хост с JMX интерфейсом 127.0.0.1:9999.
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 6
Если мы сейчас просто возьмём стандартный шаблон "Template App Generic Java JMX" и прилинкуем его к хосту, то наверняка получим ошибку:

$ tail -f /tmp/zabbix_java.log

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 7
Java Gateway сообщает нам, что по указанному endpoint отвечает совсем не RMI. Хорошо, мы уже знаем, что эта версия JBoss использует протокол JBoss Remoting вместо RMI, и нам нужно лишь начать стучаться в правильный endpoint.

Давайте сделаем Full Clone шаблона "Template App Generic Java JMX" и назовём его "Template App Generic Java JMX-remoting". Выделим все элементы данных внутри этого шаблона и выполним операцию Mass update для параметра JMX endpoint. Пропишем такой URL:

service:jmx:remoting-jmx://{HOST.CONN}:{HOST.PORT}

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 8

Обновим конфигурационный кэш:

$ /usr/local/sbin/zabbix_server -R config_cache_reload

И снова ошибка.
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 9
Что на этот раз?
“Unsupported protocol: remoting-jmx” означает, что Java Gateway не умеет работать с указанным протоколом. Что ж, давайте его научим. В этом нам поможет совет из статьи "JBoss EAP 6 monitoring using remoting-jmx and Zabbix".

Создадим файл ~/needed_modules.txt со следующим содержимым:

jboss-as-remoting
jboss-logging
jboss-logmanager
jboss-marshalling
jboss-remoting
jboss-sasl
jcl-over-slf4j
jul-to-slf4j-stub
log4j-jboss-logmanager
remoting-jmx
slf4j-api
xnio-api
xnio-nio

Выполним команду:

$ for i in $(cat ~/needed_modules.txt); do find /opt/jboss-eap-6.4 -iname ${i}*.jar -exec cp {} /usr/local/sbin/zabbix_java/lib/ ; ; done

Таким образом, Java Gateway будет иметь все необходимые модули для работы с jmx-remoting. Остаётся лишь перезапустить Java Gateway, немного подождать и, если вы всё сделали правильно, увидеть, что заветные данные начали поступать в Zabbix:
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 10
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 11

А что там с JMX обнаружением?

JMX обнаружение появилось в Zabbix одновременно с появлением нативной поддержки мониторинга Java приложений через JMX. За эту функцию отвечает недокументированный (на тот момент) ключ jmx.discovery. В документации о нём не было ни слова, потому что это была ещё очень сырая функция:
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 12

  1. В таком обнаружении нет особого смысла, потому что нет никаких возможностей для фильтрации. А вряд ли кому-то требуется обнаруживать все существующие JMX-объекты.
  2. Это очень медленное решение, т.к. здесь выполняется по одному запросу на каждый MBean, а их может быть довольно много. Очень вероятно, что такая проверка просто отвалится по таймауту.
  3. В таком виде можно создать лишь одно правило обнаружения в рамках хоста, что весьма печально, потому что на практике хотелось бы создавать множество правил (банально могут отличаться типы данных для разных атрибутов).

В Zabbix 3.4 появилась возможность фильтрации, что сразу решает многие проблемы.
Новая проверка выглядит так: jmx.discovery[<режим обнаружения>,<имя объекта>]
И позволяет указать, требуется ли обнаружение MBean'ов или их атрибутов, а также по какому шаблону их искать.
Давайте попробуем её в деле! Замониторим, к примеру, сборщики мусора. Известно, что их имена могут различаться в зависимости от того, с какими параметрами запущена JVM. А значит мы не можем задать статичные имена и ключи для элементов данных — это работёнка как раз для jmx.discovery.
Документация описывает нам четыре примера использования:

Ключ Описание
jmx.discovery Получение всех JMX MBean атрибутов
jmx.discovery[beans] Получение всех JMX MBeans
jmx.discovery[attributes,"*:type=GarbageCollector,name=*"] Получение всех атрибутов сборщика мусора
jmx.discovery[beans,"*:type=GarbageCollector,name=*"] Получение всех сборщиков мусора

Первые два варианта мы использовать не будем, т.к. это не очень хорошо с точки зрения производительности. Посмотрим, что возвращают нам два последних.
Для этой цели мы можем просто создать item с нужным нам ключом и текстовым типом данных. Но это не очень удобно. Во-первых, вывод будет неформатированным и ненаглядным. Во-вторых, чтобы изменить запрос, нам всякий раз придётся изменять ключ item'а и какое-то время ждать обновления данных.

Это не наш путь. Давайте лучше сделаем что-то вроде zabbix_get, только вместо агента будем обращаться к Java Gateway. Для этого немного доработаем предложенный в этой заметке скрипт под новый API: добавим jmx_endpoint в запрос и поправим удаление заголовка из ответа:

#!/usr/bin/env bash

if [ $# != 6 ]
then
    echo "Usage: $0 <JAVA_GATEWAY_HOST> <JAVA_GATEWAY_PORT> <JMX_SERVER> <JMX_PORT> <JMX_ENDPOINT> <KEY>"
    exit;
fi

# create connection
exec 3<>/dev/tcp/$1/$2

# compose message
MSG="{"request": "java gateway jmx", "conn": "$3", "port": $4, "jmx_endpoint": "$5", "keys": ["$6"]}"

# write message length as zero-padded 16-digit hexadecimal number
printf -v LEN '%016x' "${#MSG}"

# prepare message length in little endian representation
BYTES=""
for i in {0..14..2}
do
    BYTES="\x${LEN:$i:2}$BYTES"
done

# prepend protocol header and message length
printf "ZBXD\1$BYTES%s" "$MSG" >&3

# output the result skipping 6 bytes of "ZBXD\1" header and 8 bytes of message length
tail -c+14 <&3

Теперь мы с лёгкостью можем посмотреть, что возвращает нам шлюз в ответ на наши запросы:

$ ./zabbix_get_java.sh 127.0.0.1 10052 127.0.0.1 9999 'service:jmx:remoting-jmx://127.0.0.1:9999' 'jmx.discovery[beans,"*:type=GarbageCollector,name=*"]' | jq '.data[0].value | fromjson | .data'

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 13
Новые возможности мониторинга Java приложений в Zabbix 3.4 - 14
То что нужно!
Если бы нам требовалась, допустим, всего пара метрик, то мы могли бы обнаружить все gc и создать на каждую метрику по прототипу.

  1. Создаём правило обнаружения. Ищем MBean'ы (кстати, обратите внимание, что везде используется кастомный JMX endpoint).
    Новые возможности мониторинга Java приложений в Zabbix 3.4 - 15
  2. Создаём прототипы на каждую интересующую нас метрику. В имени элемента данных и его ключе мы можем использовать любые макросы, которые видели в JSON'е.
    Новые возможности мониторинга Java приложений в Zabbix 3.4 - 16

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 17

Кстати, о макросах. При обнаружении MBean'ов макросы генерируются динамически на основе свойств MBean'ов (таких как type и name).

Обратите внимание на эту проблему при использовании динамических макросов: https://support.zabbix.com/browse/ZBX-12705

Но, допустим, мы хотим создать все доступные числовые метрики по сборщикам мусора.

  1. Тогда мы создадим правило обнаружения атрибутов с фильтром по типу данных.
    Новые возможности мониторинга Java приложений в Zabbix 3.4 - 18

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 19

  1. И всего лишь один прототип:
    Новые возможности мониторинга Java приложений в Zabbix 3.4 - 20

Новые возможности мониторинга Java приложений в Zabbix 3.4 - 21

Вот таким нехитрым образом можно замониторить любое Java приложение. Дерзайте! :)

У меня сейчас нет возможности обновиться на Zabbix 3.4, как мне быть?

Сообщество придумало множество способов как обойти эту проблему. Если у вас пока нет возможности обновиться на эту версию, то вот вам ссылки: раз и два.

Итог

Благодаря новым реализованным возможностям мониторинг Java приложений в Zabbix перестал быть болью. Напротив, с каждой новой версией это становится всё более простым и приятным занятием :) Будем стараться радовать вас и дальше!

Stay tuned!

P.S. Статья также доступна на английском языке в нашем блоге.
P.S.S. Статьи о других нововведениях Zabbix 3.4:

Список использованной литературы

Автор: Вадим Ипатов

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js