Статьи

cjmx: версия JConsole для командной строки

JConsole — хороший инструмент для мониторинга работающего Java-приложения. Но когда невозможно подключиться к JVM напрямую с помощью JConsole (например, из-за сетевых ограничений) и туннелирование SSH невозможно, было бы здорово иметь версию JConsole для командной строки.

jcmx — это такая версия командной строки JConsole. После загрузки одного jar-файла cjmx_2.10-2.1.0-app.jar вы можете запустить его, включив tools.jar в classpath:

1
java -cp $JAVA_HOME/lib/tools.jar:cjmx_2.10-2.1.0-app.jar cjmx.Main

Откроется «оболочка JMX» со следующими основными командами:

  • help : показывает основной экран справки, который объясняет доступные команды.
  • jps / list : Как и инструмент jps из JDK, эта команда печатает все процессы Java с их идентификатором процесса.
  • connect : вы можете использовать эту команду для подключения к работающему процессу JVM.
  • формат : давайте вам укажем, хотите ли вы вывод в простом текстовом формате или в виде строки JSON.
  • выход : выход из приложения.

Чтобы узнать больше о cjmx, давайте запустим сеанс и подключимся к JVM, на которой запущен сам cjmx:

1
2
3
4
5
6
7
8
9
> jps
13198 cjmx.Main
> connect 13198
Connected to local virtual machine 13198
Connection id: rmi://0:0:0:0:0:0:0:1  2
Default domain: DefaultDomain
5 domains registered consisting of 19 total MBeans
>
describe     disconnect   exit         format       help         invoke       mbeans       names        names        sample       select       status

После последнего появления> вы видите замечательную особенность cjmx: автозаполнение. Каждый раз, когда вы не знаете, какие команды доступны, вы можете просто ввести [TAB] и cjmx выведет их список. Это даже работает для имен MBean, как мы увидим.

Теперь, когда мы подключены к нашей JVM, мы можем позволить cjmx описать доступный MBean. С помощью автозаполнения мы можем просто начать вводить describe '[TAB] чтобы получить список всех доступных пакетов:

1
2
> describe '
:                     JMImplementation:     com.sun.management:   java.lang:            java.nio:             java.util.logging:

Таким образом, мы можем копаться в именах MBean, пока не найдем то, что ищем. В этом примере нас интересует MBean ‘java.lang: type = OperatingSystem’:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
> describe 'java.lang:type=OperatingSystem'
Object name: java.lang:type=OperatingSystem
-------------------------------------------
Description: Information on the management interface of the MBean
 
Attributes:
  MaxFileDescriptorCount: long
  OpenFileDescriptorCount: long
  FreePhysicalMemorySize: long
  CommittedVirtualMemorySize: long
  FreeSwapSpaceSize: long
  ProcessCpuLoad: double
  ProcessCpuTime: long
  SystemCpuLoad: double
  TotalPhysicalMemorySize: long
  TotalSwapSpaceSize: long
  AvailableProcessors: int
  Arch: String
  SystemLoadAverage: double
  Name: String
  Version: String
  ObjectName: ObjectName

Как мы видим, MBean ‘java.lang: type = OperatingSystem’ предоставляет информацию о количестве открытых файлов и текущей загрузке процессора и т. Д. Итак, давайте mbeans количество открытых файлов, вызвав команду mbeans с именем MBean, а также подкоманда select и атрибут MBean:

1
2
3
4
> mbeans 'java.lang:type=OperatingSystem' select OpenFileDescriptorCount
java.lang:type=OperatingSystem
------------------------------
  OpenFileDescriptorCount: 35

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

1
2
3
4
5
6
> mbeans 'java.lang:type=OperatingSystem' select *
java.lang:type=OperatingSystem
------------------------------
  MaxFileDescriptorCount: 10240
  OpenFileDescriptorCount: 36
...

С помощью invoke мы можем даже вызвать методы MBean, как в следующем примере:

1
2
> mbeans 'java.lang:type=Memory' invoke gc()
java.lang:type=Memory: null

Теперь, когда мы знаем, как запрашивать атрибуты и вызывать методы, мы можем приступить к созданию сценариев этой функции для мониторинга приложения. Для поддержки этого вида сценариев cjmx предоставляет возможность передавать все «команды» также в качестве аргумента самого приложения, поэтому вы можете вызывать cjmx следующим образом (где <PID> должен быть заменен конкретным процессом). идентификатор работающей JVM):

1
2
3
4
java -cp $JAVA_HOME/lib/tools.jar:cjmx_2.10-2.1.0-app.jar cjmx.Main &amp;lt;PID&amp;gt; &amp;quot;mbeans 'java.lang:type=OperatingSystem' select OpenFileDescriptorCount&amp;quot;
java.lang:type=OperatingSystem
------------------------------
  OpenFileDescriptorCount: 630

Обладая этими знаниями, мы можем написать простой скрипт bash, который каждую секунду запрашивает у JVM количество открытых файлов:

1
2
3
4
5
6
#!/bin/bash
while [ true ] ; do
        echo `date` | tr -d '\n'
        java -cp /usr/java/default/lib/tools.jar:cjmx_2.10-2.1.0-app.jar cjmx.Main $1 &amp;quot;mbeans 'java.lang:type=OperatingSystem' select OpenFileDescriptorCount&amp;quot;|grep OpenFileDescriptorCount|cut -f 2 -d :
        sleep 1
done

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

Вывод : cjmx является отличной альтернативой JConsole, когда последний не может быть использован из-за сетевых ограничений на сервере. Возможность даже выдавать команды, передавая их в командной строке, делает его подходящим для небольших сценариев мониторинга.

Ссылка: cjmx: версия JConsole для командной строки от нашего партнера по JCG Мартина Мойса из блога Martin’s Developer World .