Вышел долгожданный релиз Zabbix 3.4, который принёс много полезных улучшений, среди которых оказались настраиваемые JMX endpoints и гибкое обнаружение MBean’ов. Если вы используете Zabbix и вам требуется мониторить Java приложения, то да — это может сильно облегчить вам жизнь, потому что раньше приходилось прибегать к различным ухищрениям, а теперь всё работает, как говорится, “из коробки”.  Нативный мониторинг Java приложений через JMX появился в Zabbix давно — начиная с версии 2.0 — и с тех пор этот функционал улучшается от версии к версии. Но так вышло, что в предыдущих релизах JMX endpoint был жёстко зашит в код Zabbix Java Gateway совершенно наивным образом.

Как выяснилось, в мире 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 (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 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 Но на самом деле не всё так страшно.

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

url-path часть означает буквально следующее: возьми ту часть URL, которая следует сразу за /jndi/ и выполни по этому адресу JNDI-запрос в RMI registry, чтобы получить информацию об RMI-сервере. Реестр вернёт в ответ его хост и порт.
Следует отметить, что порт в таком случае генерируется случайным образом и могут возникнуть проблемы с настройкой файрвола. В таких случаях и используют предыдущий вариант записи JMX endpoint’а, потому что он позволяет явно указать порт. Если вам хотелось бы глубже разобраться в JMX, то рекомендуем обратиться к официальной документации Oracle. Нет ничего проще :) Давайте для примера попробуем настроить мониторинг JBoss EAP 6.4. Для начала сделаем несколько предположений: Сделаем несколько простых настроек в zabbix_server.conf: И в конфиге zabbix_java/settings.sh (или zabbix_java_gateway.conf): Проверьте, что JBoss слушает свой стандартный management port: Теперь давайте создадим в Zabbix хост с JMX интерфейсом 127.0.0.1:9999.

Если мы сейчас просто возьмём стандартный шаблон "Template App Generic Java JMX" и прилинкуем его к хосту, то наверняка получим ошибку: 
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}  Обновим конфигурационный кэш: И снова ошибка.

Что на этот раз?
“Unsupported protocol: remoting-jmx” означает, что Java Gateway не умеет работать с указанным протоколом. Что ж, давайте его научим. В этом нам поможет совет из статьи "JBoss EAP 6 monitoring using remoting-jmx and Zabbix". Создадим файл ~/needed_modules.txt со следующим содержимым: Выполним команду: Таким образом, Java Gateway будет иметь все необходимые модули для работы с jmx-remoting. Остаётся лишь перезапустить Java Gateway, немного подождать и, если вы всё сделали правильно, увидеть, что заветные данные начали поступать в Zabbix:

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

То что нужно!
Если бы нам требовалась, допустим, всего пара метрик, то мы могли бы обнаружить все gc и создать на каждую метрику по прототипу.  Кстати, о макросах. При обнаружении MBean'ов макросы генерируются динамически на основе свойств MBean'ов (таких как type и name).  Но, допустим, мы хотим создать все доступные числовые метрики по сборщикам мусора.   Вот таким нехитрым образом можно замониторить любое Java приложение. Дерзайте! :) Сообщество придумало множество способов как обойти эту проблему. Если у вас пока нет возможности обновиться на эту версию, то вот вам ссылки: раз и два. Благодаря новым реализованным возможностям мониторинг Java приложений в Zabbix перестал быть болью. Напротив, с каждой новой версией это становится всё более простым и приятным занятием :) Будем стараться радовать вас и дальше! P.S. Статья также доступна на английском языке в нашем блоге.
P.S.S. Статьи о других нововведениях Zabbix 3.4: Monitoring systems