Статьи

Swiss Java Knife — Полезный инструмент для добавления в ваш диагностический набор инструментов?

Как консультант службы поддержки в C2B2 я всегда ищу удобные инструменты, которые могут помочь мне или моей команде в диагностике проблем промежуточного программного обеспечения наших клиентов. Итак, когда я наткнулся на проект под названием Swiss Java Knife, обещающий инструменты для «мониторинга, профилирования и настройки JVM», я подумал, что стоит взглянуть. Это в основном один файл JAR, который позволяет вам запускать ряд инструментов, большинство из которых похожи на те, которые поставляются в комплекте с JDK.

Если вы заинтересованы в этих инструментах, мой коллега Мэтт Браузер провел хороший вводный вебинар, который можно найти здесь:

http://www.c2b2.co.uk/jvm_webinar_video

Загрузка

Сначала я скачал последний файл jar с github:

https: // github.com/aragozin/jvm-tools

Исходный код также доступен, но для целей этого взгляда на то, что он может предложить, достаточно jar.

Что это предлагает?

Swiss Java Knife предлагает ряд команд:

jps — аналогично инструменту jps, который поставляется с JDK.
ttop — аналогично верхней команде linux.
hh — аналогично запуску инструмента jmap, который поставляется с JDK с параметром -histo.
gc — сообщает информацию о GC в режиме реального времени.
mx — позволяет выполнять основные операции с MBeans из командной строки.
mxdump — сбрасывает все MBean целевого Java-процесса в JSON.

тестирование

Чтобы протестировать доступные команды, я настроил сервер Weblogic и развернул приложение, содержащее ряд сервлетов с известными проблемами. Затем они вызываются через JMeter, чтобы показать определенное поведение сервера:

  • чрезмерная сборка мусора
  • высокая загрузка процессора
  • утечка памяти

Поиск идентификатора процесса

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

Swiss Java Knife имеет свою собственную версию команды jps, поэтому я попробовал это.

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

java -jar sjk-plus-0.1-2013-09-06.jar jps

дает следующий вывод:

5402org.apache.derby.drda.NetworkServerControl start
3250weblogic.Server
4032./ApacheJMeter.jar
3172weblogic.NodeManager -v
5427weblogic.Server
6523sjk-plus-0.1-2013-09-06.jar jps

Что в основном аналогично запуску команды
jps с опцией -l.

Есть пара дополнений, в которых вы можете добавить опции фильтра, позволяющие передавать
групповые символы для соответствия описаниям процессов или свойствам системы JVM, но в целом это очень мало добавляет к стандартному
инструменту jps .

jps -lv , как правило, даст вам все, что вам нужно.


Итак, теперь у нас есть идентификатор процесса нашего сервера, и мы можем начать смотреть на то, что происходит.
Прежде всего, давайте проверим сборку мусора.
Проверка сборки мусора

ОК. Теперь этот выглядит более перспективным. Swiss Java Knife имеет команду для сбора статистики GC в реальном времени. Давайте попробуем.

Итак, выполнение следующей команды без запуска моего хитрого сервлета должно дать нам «стандартное» чтение:

java -jar sjk-plus-0.1-2013-09-06.jar gc -p 3016
[GC: PS Scavenge#10471 time: 6ms interval: 113738ms mem: PS Survivor Space: 0k+96k->96k[max:128k,rate:0.84kb/s] PS Old Gen: 78099k+0k->78099k[max:349568k,rate:0.00kb/s] PS Eden Space: 1676k-1676k->0k[max:174464k,rate:-14.74kb/s]]
[GC: PS MarkSweep#10436 time: 192ms interval: 40070ms mem: PS Survivor Space: 96k-96k->0k[max:128k,rate:-2.40kb/s] PS Old Gen: 78099k+7k->78106k[max:349568k,rate:0.19kb/s] PS Eden Space: 0k+0k->0k[max:174400k,rate:0.00kb/s]]

PS Scavenge[ collections: 31 | avg: 0.0057 secs | total: 0.2 secs ]
PS MarkSweep[ collections: 9 | avg: 0.1980 secs | total: 1.8 secs ]

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

После запуска моего хитрого сервлета (содержащего несколько вызовов System.gc ()) мы видим следующее:

[GC: PS Scavenge#9787 time: 5ms interval: 38819ms mem: PS Survivor Space: 0k+64k->64k[max:192k,rate:1.65kb/s] PS Old Gen: 78062k+0k->78062k[max:349568k,rate:0.00kb/s] PS Eden Space: 204k-204k->0k[max:174336k,rate:-5.28kb/s]]
[GC: PS MarkSweep#10200 time: 155ms interval: 112488ms mem: PS Survivor Space: 64k-64k->0k[max:192k,rate:-0.57kb/s] PS Old Gen: 78071k+0k->78071k[max:349568k,rate:0.00kb/s] PS Eden Space: 0k+0k->0k[max:174336k,rate:0.00kb/s]]

PS Scavenge[ collections: 666 | avg: 0.0046 secs | total: 3.1 secs ]
PS MarkSweep[ collections: 689 | avg: 0.1588 secs | total: 109.4 secs ]

Большая разница и, хотя это не очень реалистичный сценарий, это, безусловно, полезный инструмент для возможности быстрого просмотра информации GC во время выполнения.

Далее мы рассмотрим использование процессора.

Проверка использования ЦП В

швейцарском Java-ноже есть команда, которая работает аналогично команде linux
top, которая отображает основные процессы ЦП.

Выполнение следующей команды должно дать нам 10 лучших процессорных процессов при нормальной работе:

java -jar sjk-plus-0.1-2013-09-06.jar ttop -n 10 -p 5427 -o CPU

2014-03-11T08:56:33.120-0700 Process summary
  process cpu=2.21%
  application cpu=0.67% (user=0.30% sys=0.37%)
  other: cpu=1.54%
  heap allocation rate 245kb/s
[000001] user= 0.00% sys= 0.00% alloc=     0b/s - main
[000002] user= 0.00% sys= 0.00% alloc=     0b/s - Reference Handler
[000003] user= 0.00% sys= 0.00% alloc=     0b/s - Finalizer
[000004] user= 0.00% sys= 0.00% alloc=     0b/s - Signal Dispatcher
[000010] user= 0.00% sys= 0.00% alloc=     0b/s - Timer-0
[000011] user= 0.00% sys= 0.01% alloc=    96b/s - Timer-1
[000012] user= 0.00% sys= 0.01% alloc=    20b/s - [ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'
[000013] user= 0.00% sys= 0.00% alloc=     0b/s - weblogic.time.TimeEventGenerator
[000014] user= 0.00% sys= 0.04% alloc=   245b/s - weblogic.timers.TimerThread
[000017] user= 0.00% sys= 0.00% alloc=     0b/s - Thread-7

Пока все хорошо, минимальное использование процессора. Теперь я запустил свой хитрый сервлет и запустил его снова:

Хм, не очень хорошо:

Неожиданная ошибка: java.lang.IllegalArgumentException: метод сравнения нарушает его общий контракт!

Попробуйте еще раз, и мы получим следующее:

2014-03-11T09:00:10.625-0700 Process summary
  process cpu=199.14%
  application cpu=189.87% (user=181.57% sys=8.30%)
  other: cpu=9.27%
  heap allocation rate 4945kb/s
[000040] user=83.95% sys= 2.82% alloc=     0b/s - [ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'
[000038] user=93.71% sys=-0.44% alloc=     0b/s - [ACTIVE] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'
[000044] user= 3.90% sys= 4.91% alloc= 4855kb/s - RMI TCP Connection(5)-127.0.0.1
[000001] user= 0.00% sys= 0.00% alloc=     0b/s - main
[000002] user= 0.00% sys= 0.00% alloc=     0b/s - Reference Handler
[000003] user= 0.00% sys= 0.00% alloc=     0b/s - Finalizer
[000004] user= 0.00% sys= 0.00% alloc=     0b/s - Signal Dispatcher
[000010] user= 0.00% sys= 0.00% alloc=     0b/s - Timer-0
[000011] user= 0.00% sys= 0.04% alloc=  1124b/s - Timer-1
[000012] user= 0.00% sys= 0.00% alloc=     0b/s - [STANDBY] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'

Таким образом, использование процессора теперь находится на высоте (как и ожидалось).

Основная проблема с этим заключается в том, что, подобно команде
jps, она не предлагает намного больше, чем команда
top . Он также выдавал исключение выше много раз при попытке запуска команд, упорядоченных ЦП.

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

Наконец, мы посмотрим на использование памяти.

Проверка использования памяти

Для проверки использования памяти Swiss Java Knife имеет инструмент под названием
hh, который, как он утверждает, является расширенной версией
jmap -histo. Для тех, кто не знаком с
Jmapэто еще один инструмент, поставляемый с JDK, который печатает карты памяти совместно используемых объектов или детали памяти кучи для процесса.

Итак, во-первых, я запускаю тест JMeter, который неоднократно вызывает мой хитрый сервлет. На этот раз тот, который выделяет несколько байтовых массивов каждый раз, когда он вызывается для имитации утечки памяти.

Несмотря на то, что он претендует на то, чтобы быть расширенной версией
jmap -histo, единственным реальным дополнением является возможность указать, сколько сегментов для просмотра, но этого легко достичь, передавая вывод
jmap -histo через head. Помимо этого выход практически идентичен.

Вывод из jmap:

 num #instances # байтовое имя класса

————————————— ——-

   1: 42124 234260776 [B

   2: 161472 24074512 <constMethodKlass>

   3: 161472 21970928 <methodKlass>

   4: 12853 15416848 <constantPoolKlass>

   5: 12853 10250656 <instanceKlassKlass>

   6: 84735 9020400 [константа C

   7: 10896 8910 810 843)

   1043C: 8: 8 8 8 8 8 8 843 843 843 843 81043 2939936 java.lang.String

   9: 14021 1675576 ​​java.lang.Class

  10: 10311 1563520 [Ljava.lang.Object;

  Вывод из sjk:

  java -jar sjk-plus-0.1-2013-09-06.jar hh -n 10 -p 5427

    1: 56626 386286072 [B

   2: сто шестьдесят одна тысяча четыреста девяносто три 24076192 <constMethodKlass>

   3: сто шестьдесят одна тысяча четыреста девяносто три 21973784 <methodKlass>

   4: 12850 15409912 <constantPoolKlass>

   5: 12850 10249384 <instanceKlassKlass>

   6: 10891 8936672 <constantPoolCacheKlass>

   7: 83336 8577720 [С

   8: 90525 2896800 java.lang.String

   9: 14018 1675264 java.lang.Class

  10: 9819 1579400 [Ljava.lang.Object;

Итого 996089 500086120

Единственными доступными инструментами являются команды mxdump и mx, которые разрешают доступ к атрибутам и операциям MBean.

Однако попытка выполнить любой из них привела к
исключению нулевого указателя. 

В этот момент я обычно загружал код и начинал ковыряться, но к настоящему моменту я уже видел достаточно.

Заключение

Хотя хорошая идея, она очень ограничена в том, что она предлагает. Под прикрытием он использует Attach API, поэтому для его работы требуется JDK, а не только JRE, поэтому большинство доступных инструментов уже снабжены стандартным JDK. Есть несколько дополнений к этим инструментам, но ничто так не оправдывает их использование.

Единственный инструмент, который я мог бы использовать сам, — это инструмент сбора данных ГХ в реальном времени, но он будет полезен только тогда, когда журналы ГХ недоступны, а другие инструменты мониторинга недоступны.

Количество ошибок, замеченных при выполнении основных команд, также вызывало беспокойство, хотя это всего лишь проект на github, а не коммерческое предложение, и он не выглядит особенно активным.

Итак, полезный инструмент для добавления в ваш диагностический набор инструментов? Не по моему мнению. Это, безусловно, интересная идея, и дальнейшая работа может быть полезной, но сейчас я бы остановился на инструментах, которые уже доступны.