- PVSM.RU - https://www.pvsm.ru -

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

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

Вышел долгожданный релиз 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 [1] вместо RMI [2] и JMXServiceURL для него должен выглядеть так:

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

А, например, WebSphere 8.5 использует RMI поверх IIOP [3] (а не JRMP [4]) и для него 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 [5]). Если говорить строже, то это адрес коннектор-сервера JMX API. Формат этого адреса определяется RFC 2609 [6] и RFC 3111 [7]. В общем случае он выглядит так:

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 [8] (каталог, где регистрируются RMI-серверы). По умолчанию: 1099.

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

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

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

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

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

  1. Вы уже установили Zabbix 3.4 и Zabbix Java Gateway. Если еще нет, то вы можете сделать это в соответствии с документацией Zabbix [12].
  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" [13].

Создадим файл ~/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.
Документация [14] описывает нам четыре примера использования:

Ключ Описание
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. Для этого немного доработаем предложенный в этой заметке [15] скрипт под новый 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 [16]

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

  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, как мне быть?

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

Итог

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

Stay tuned!

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

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

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

Источник [30]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/java/268442

Ссылки в тексте:

[1] JBoss Remoting: https://developer.jboss.org/wiki/Remoting

[2] RMI: https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/

[3] RMI поверх IIOP: https://www.ibm.com/support/knowledgecenter/en/SSYKE2_9.0.0/com.ibm.java.multiplatform.90.doc/rmi-iiop/overview.html

[4] JRMP: https://en.wikipedia.org/wiki/Java_Remote_Method_Protocol

[5] JMXServiceURL: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/javax/management/remote/JMXServiceURL.java

[6] RFC 2609: https://tools.ietf.org/html/rfc2609

[7] RFC 3111: https://www.ietf.org/rfc/rfc3111.txt

[8] RMI registry: https://stackoverflow.com/questions/5658929/what-is-rmi-registry

[9] JNDI-запрос: https://docs.oracle.com/javase/jndi/tutorial/getStarted/overview/index.html

[10] используют предыдущий вариант: https://docs.oracle.com/javase/9/management/monitoring-and-management-using-jmx-technology.htm#JSMGM-GUID-34811D07-AB51-4EC7-8D37-EEAF7C15F5C7

[11] официальной документации Oracle: https://docs.oracle.com/javase/9/jmx/toc.htm

[12] документацией Zabbix: https://www.zabbix.com/documentation/3.4/ru/manual/concepts/java

[13] "JBoss EAP 6 monitoring using remoting-jmx and Zabbix": https://www.denniskanbier.nl/blog/monitoring/jboss-eap-6-monitoring-using-remoting-jmx-and-zabbix/

[14] Документация: https://www.zabbix.com/documentation/3.4/ru/manual/discovery/low_level_discovery/jmx

[15] этой заметке: https://zabbix.org/wiki/Docs/howto/zabbix_get_jmx

[16] https://support.zabbix.com/browse/ZBX-12705: https://support.zabbix.com/browse/ZBX-12705

[17] раз: https://bitbucket.org/ryanrupp/zabbix-java-gateway/wiki/Home

[18] два: https://github.com/RiotGamesMinions/zabbix_jmxdiscovery

[19] нашем блоге: http://blog.zabbix.com/new-monitoring-possibilities-for-java-applications-in-zabbix-3-4/

[20] Обзор Zabbix 3.4: https://habrahabr.ru/company/zabbix/blog/336084/

[21] О массовом сборе данных и препроцессинге: https://habrahabr.ru/company/zabbix/blog/337856/

[22] http://java-course.ru/articles/jmx/: http://java-course.ru/articles/jmx/

[23] http://www.javaspecialist.ru/2011/04/jmx-firewall.html: http://www.javaspecialist.ru/2011/04/jmx-firewall.html

[24] https://docs.oracle.com/javase/tutorial/jmx/remote/index.html: https://docs.oracle.com/javase/tutorial/jmx/remote/index.html

[25] https://dzone.com/articles/remote-jmx-access-wildfly-or: https://dzone.com/articles/remote-jmx-access-wildfly-or

[26] https://habrahabr.ru/post/225527/: https://habrahabr.ru/post/225527/

[27] https://jcp.org/en/jsr/detail?id=160: https://jcp.org/en/jsr/detail?id=160

[28] https://www.ibm.com/developerworks/ru/library/j-jtp09196/index.html: https://www.ibm.com/developerworks/ru/library/j-jtp09196/index.html

[29] https://www.ixxus.com/blog/blog201102monitor-and-manage-alfresco-jmx/: https://www.ixxus.com/blog/blog201102monitor-and-manage-alfresco-jmx/

[30] Источник: https://habrahabr.ru/post/342226/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best