Мониторинг «на коленке» – использование Cacti для контроля Jаva приложений

от автора

В статье описывается решение для мониторинга с использованием Cacti на примере задачи анализа и контроля потребления ресурсов большого Java-приложения.

Передо мной стояла задача – в краткие сроки предложить меры по стабилизации большого трехзвенного Java-приложения, имеющего проблемы с потреблением памяти и производительностью. Времени, как обычно, мало: 1-2 недели на все. На фирме отсутствовала подходящая инфраструктура мониторинга приложений, и в мою задачу не входило ее создавать. Вариант с использованием JConsole не подходил из-за необходимости анализировать потребление за продолжительное время и смотреть его после возможных внезапных перезагрузок приложений.

В одной из фирм, где я работал, было реализовано впечатляющее по удобству и простоте решение для мониторинга Java-приложений на основе RRD Tool. Состояло оно из несложной надстройки на perl-скриптах, обеспечивающих сбор и отображение данных через HTTP и ряда доработок-агентов сбора данных в самом приложении. Для меня это стало идеей решения, однако, времени на написание обвязки над RRD у меня не было.

После аккуратного поиска нашелся бесплатный инструмент, реализующий необходимую мне надстройку – Cacti. Cacti это приложение, написанное в инфраструктуре Apache-PHP-MySql, позволяющее настраивать сбор и отображение данных мониторинга на основе веб-интерфейса. Разобраться с ним оказалось несложно, пару дней для подъема инфраструктуры, затем настройка и дописывание агентов сбора данных и все.

Далее в статье подробно описывается решение, позволившие решить мою задачу и, в конце концов, провести успешную стабилизацию приложения на фирме.

Что нужно для работы:

  • Cacti 0.8.7i (самая свежая версия на момент реализации решения)
  • Apache 2.2.21 (движок для Cacti)
  • PHP 5.3.8 (платформа, на которой написана Cacti)
  • MySQL 5.5 (хранение настроек Cacti)
  • RRDTool 1.2.30 (отрисовка диаграмм и хранение данных мониторинга)

(указаны версии, на которых запустился мониторинг, подойдет любая работающая связку Apache-PHP-MySql)

Опишу принцип работы мониторинга на Cacti: при помощи «назначенных заданий» Windows (или cron в unix) производится периодический запуск опроса (polling) агентов сбора данных, которыми в моем случае были: сама JVM (потребление памяти) и специализированные доработки приложения. Собранные сведения размещаются в базе данных RRD – т.е. в циклических буферах в виде файлов. Далее, накопленные данные из RRD можно просматривать через веб-интерфейс Cacti в различных масштабах в разрезе минут, часов, дней, месяцев, др.

План работы – поднять всю необходимую инфраструктуру, адаптировать анализируемые приложения для сбора данные и настроить сбор и вывод данных в Cacti.

Настройка инфраструктуры

PHP

Добавить путь к php.exe в переменную PATH, тот же путь прописать в переменной PHPRC

Скопировать файл php.ini-production в php.ini и внести в php.ini следующие изменения:

Раскомментировать строчки:

 extension_dir = c:\php\ext extension=php_mysql.dll extension=php_snmp.dll extension=php_sockets.dll cgi.force_redirect = 0 date.timezone = "Europe/Moscow" 
Apache

Добавить в conf\httpd.conf следующие строки:

 LoadModule php5_module c:\php\php5apache2_2.dll AddType application/x-httpd-php .php DirectoryIndex index.html index.htm index.php 
MySql

Добавить путь к mysql.exe в переменную PATH

Создание схемы cacti:

 mysql --user=root --password create cacti 

Импортируем структуру данных схемы cacti

 mysql --user=root --password cacti < c:\apache2\htdocs\cacti\cacti.sql 

Создаем пользователя cactiuser:

 mysql --user=root --password  

Далее в командной строке MySql:

 mysql> create user cactiuser@localhost IDENTIFIED BY ’cactiuser’ mysql> GRANT ALL ON cacti.* TO cactiuser@localhost; mysql> flush privileges; 

Для быстрой проверки работоспособности связки php-mysql-apache я использовал следующих скрипт php:

 <?php mysql_connect( "localhost", "cactiuser", "cactiuser" ) or die("Can't connect"); mysql_query( "USE cacti" ) or die("Can't select mysql database"); echo "Success\n"; ?> 

Его надо положить в файлик с именем, например, testphp.php, скопировать в директорию Apache htdocs/ и загрузить страничку localhost:8080/testphp.php. Должна появиться надпись «Success».

Настройка Cacti

Разархировать дистрибутив cacti в директорию Apache /htdocs.
Проверить что файл cacti /include/config.php содержит следующие строки:

 $database_default = "cacti"; $database_hostname = "localhost"; $database_username = "cactiuser"; $database_password = "cactiuser"; $database_port = "3306"; 

Зайти на адрес localhost:8080/cacti/ под логином admin/admin.

В настройках Settings->Paths задать пути к внешним утилитам (рекомендуется использовать пути в стиле Unix, например c:/php/php.exe).

Настроить запуск команды «php cacti/poller.php» каждые 5 минут (через Windows Scheduled Tasks). У меня для этого используется батничек:

 start /MIN php.exe cacti\poller.php 

Настройка Cacti Spine (опционально: это poller, написанный на C++, который используется для ускорения опроса, рекомендуется Cacti)
Разархивировать spine архив в директорию cacti убедиться что spine.conf содержит следующие строки:

 DB_Host 127.0.0.1 # строго не localhost!!! DB_Database cacti DB_User cactiuser DB_Password cactiuser DB_Port 3306 
Выбор и настройка сбора данных

Я пробовал два способа сбора данных – SNMP и опрос JMX сервера в составе JVM и приложений. SNMP поддерживается Cacti и его разумно использовать, если нужно смотреть только использование памяти JVM и, нужно это сделать очень быстро. Я начал с SNMP, но после первых успехов перешел на JMX. Cacti не поддерживает JMX, поэтому за дополнительную гибкость надо платить — требуются усилия по написанию приемной и ответной части на Java.

Ниже привожу соответствующий код.

Код для опроса JVM по состоянию памяти (аналогично пишется код для произвольного JMX-сервера):

import java.io.Closeable; import java.io.IOException; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage;  import javax.management.JMX; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL;   public class JvmHeapJmxClient {     public static void main(String[] args) {         JMXConnector jmxc = null;         try {             String jmxHost = args[0];             String jmxPort = args[1];             String jmxConnectionString = "service:jmx:rmi:///jndi/rmi://" + jmxHost + ":" + jmxPort + "/jmxrmi";                          JMXServiceURL url = new JMXServiceURL(jmxConnectionString);             jmxc = JMXConnectorFactory.connect(url, null);             MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();              ObjectName memoryMBeanName = new ObjectName("java.lang:type=Memory");             MemoryMXBean memoryMBeanProxy = JMX.newMXBeanProxy(mbsc, memoryMBeanName, MemoryMXBean.class, true);             MemoryUsage memoryUsage = memoryMBeanProxy.getHeapMemoryUsage();                          echo(                 "used:" + memoryUsage.getUsed() + " " +                 "committed:" + memoryUsage.getCommitted() + " " +                 "init:" + memoryUsage.getInit() + " " +                 "max:" + memoryUsage.getMax());                      } catch(Exception e) {             e.printStackTrace();         } finally {             closeStream(jmxc);         }     }      private static void echo(String msg) {         System.out.println(msg);     }      private static void closeStream(Closeable stream) {         try {             if (stream != null) {                 stream.close();             }         } catch (IOException e) {             e.printStackTrace();         }     } } 

Код Java для запуска JMX. Все эти сложности нужны для фиксирования порта и имени хоста, что требуется при наличии межсетевого экрана. Для каждого сервиса требуется по 2 порта, как видно из кода – один для http доступа, другой для RMI. Распределение портов очевидно можно сделать по-другому (в данном случае RMI-порт = http-порт + 1), в том числе явно указать оба порта. В строку запуска приложений нужно будет добавить следующие слова (jmxagent – jar-файл с кодом агента):

 -Djmxagent.port=<SERVER_JMX_PORT> -Djmxagent.host=<SERVER_HOST> -javaagent:jmxagent.jar 
import java.io.IOException; import java.lang.management.ManagementFactory; import java.rmi.registry.LocateRegistry; import java.util.HashMap;  import javax.management.MBeanServer; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL;  public class JmxFirewallAgent {      private JmxFirewallAgent() { }      public static void premain(String agentArgs) throws IOException {         try {             final int rmiRegistryPort = Integer.parseInt(System.getProperty("jmxagent.port"));             LocateRegistry.createRegistry(rmiRegistryPort);                  final int rmiServerPort = rmiRegistryPort + 1;                  MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();             HashMap<String,Object> env = new HashMap<String,Object>();             final String hostname = System.getProperty("jmxagent.host");                     JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://" + hostname + ":" + rmiServerPort + "/jndi/rmi://" + hostname + ":" + rmiRegistryPort    + "/jmxrmi");                          JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);             cs.start();         } catch (Exception e) {             e.printStackTrace();         }     } } 

Далее идут скриншоты наиболее важных настроек Cacti.

Настройка опроса – важный момент в общих настройках Cacti. Я использую Spine, опрос запускается каждые 5 минут, данные снимаются каждые 10 секунд. Смотрите далее настройки RRD в составе Cacti – их требуется продумать заранее, т.к. далее менять без перезаписи базы RRD проблематично. Здесь неплохая подборка советов по этим настройкам:

Мои настройки RRD.

Пример содержимого одной настройки:

Настраивам Device – это сервер с IP-адресом, с которого будут забираться данные. У нас несколько серверов, на каждом из них запущено несколько сервисов Java.

Настраиваем Data Input Method – задание способа сбора данных. В моем случае это батничек, который запускает Java программу опроса JMX (ее исходные коды были приведены выше.) Входные параметры у него это адрес и порт сервера, т.е. Java-приложения.

Пример описания входного параметра – в данном случае адрес сервера. Используется предопределенное ключевое слово – hostname, которое автоматически заполняется Cacti. Второй параметр будет заполняться для каждой настройки сбора данных Data Source, как будет видно дальше.

Выходные параметры, которые возвращает батничек. Cacti понимает их в формате:

 ключ1:значение1 ключ2:значение2 

Моя программа возвращает 4 выходных значения, вот пример задания одного из них (commited):

Далее создаем Data Template – шаблон для задания источников данных. Самая важная настройка в Cacti, на мой взгляд. Шаблон связывается с настройкой базы RRD, в нем указываются параметры для хранения в базе (Data Source Item) и дополнительные настройки, в данном случае это jmx host и jmx port, первый, как уже говорилось, заполняется автоматически, второй будет заполняться на каждом источнике данных, т.е. источник данных будет соответствовать одному Java-приложению.

На основе шаблона создается Data Source – источник данных, которые затем можно будет отображать на диаграммах Graph. В источнике указывает Device, к которому надо подключаться для сбора данных, шаблон источника, имя и месторасположение базы данных RRD. В моем случае также требуется указать дополнительный параметр – порт JMX. Важный момент – при существенных обновлениях настроек сбора данных в Data Source или Data Template (например, удаление-добавление параметров Data Source Item) требуется пересоздание базы данных RRD. Это можно сделать руками вне Cacti (я до этого не добрался) или пересоздать Data Source с потерей всех предыдущих данных. Это, видимо, самое неприятная особенность связки Cacti-RRD, с которой мне пришлось столкнуться.

Приступаем к отображению данных путем задания шаблонов диаграмм Graph Template. Настройки в основном задают способ визуализации данных. Требуется указать параметры из Data Template, которые требуется выводить на диаграмме и в каком виде. Насколько я понимаю все эти настройки – непосредственная оболочка над командным интерфейсом RRD.

Пример задания параметра Data Source. Я использую для отображения потребления памяти 5 элементов на диаграмме: Макс, мин, и текущее потребление в виде сплошной закраски (порядок вывода важен!), затем два параметра – максимальное выделенное и зарезервированное потребление в виде линий. Пример, см. ниже.

Диаграмма Graph – задается шаблон, сервер и задание соответствия между конкретным Data Source и паметрами шаблона диаграммы:

Пример окончательной диаграммы использующей все заданные настройки: Видно что потреблениев среднем на уровне 3Гб, однако довольно часто достигает максимальной выделенной границы в 6Гб (-Xmx). Данные можно смотреть с произвольной детальностью (от 1 тика сбора до 2лет, как на примере и больше). Все это зависит от заданных настроек базы RRD. С моими настройками мне вполне хватило информации для решения проблем с потреблением.

На этом описание моего решения заканчивается. Подчеркиваю, что основная идея решения – это скорость реализации при высоком качестве полученного результата. Вопросы и идеи по улучшению приветствуются.

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

Спасибо за внимание!

Выводы:

Cacti позволил мне успешно решить задачу быстрой настройки мониторинга Java-приложений. Если вам нужно быстро с нуля сделать мониторинг – рекомендую это как один из рабочих вариантов. Если в ваши планы входит построение долгосрочного мониторинга, то, на мой взгляд, имеет смысл посмотреть на следующие варианты: внедрять мощные системы типа Nagios, либо писать свою специализированную надстройку над RRD. Плюсы и минусы Cacti:

Минусы решения:

  • Довольно быстрое нарастание количества однотипных настроек в случае большого числа сред и серверов приложений Java.
  • Ограниченная производительность «неродных» JMX решений для Cacti.

Плюсы решения:

  • Высокая скорость развертывания при минимальном дополнительном кодировании
  • Простота и удобство интерфейса просмотра диаграмм и их настройки (не нужно сразу учить что-то сложное)

ссылка на оригинал статьи http://habrahabr.ru/post/179391/


Комментарии

Добавить комментарий

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