Jprofiler как пользоваться
Перейти к содержимому

Jprofiler как пользоваться

  • автор:

Руководство по профайлерам Java

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

Java Profiler — это инструмент, который отслеживает конструкции и операции байт-кода Java на уровне JVM . Эти конструкции кода и операции включают создание объекта, итеративное выполнение (включая рекурсивные вызовы), выполнение методов, выполнение потоков и сборку мусора.

В этой статье мы обсудим основные профилировщики Java: JProfiler , YourKit , Java VisualVM и профайлер Netbeans .

2. JProfiler

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

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

Вот как выглядит интерфейс JProfiler:

./c2c880c58e83166ac7dc13832529216e.png

Как и большинство профилировщиков, мы можем использовать этот инструмент как для локальных, так и для удаленных приложений. Это означает, что можно профилировать приложения Java, работающие на удаленных машинах, без необходимости устанавливать на них что-либо .

JProfiler также обеспечивает расширенное профилирование как для баз данных SQL, так и для баз данных NoSQL . Он предоставляет специальную поддержку для профилирования баз данных JDBC, JPA/Hibernate, MongoDB, Casandra и HBase.

На приведенном ниже снимке экрана показан интерфейс зондирования JDBC со списком текущих подключений:

./4caa73239032feb6a1ac4dcb747574cb.png

Если мы заинтересованы в изучении дерева вызовов взаимодействий с нашей базой данных и видим соединения, которые могут быть упущены, JProfiler отлично с этим справится.

Live Memory — это одна из функций JProfiler, которая позволяет нам видеть текущее использование памяти нашим приложением . Мы можем просмотреть использование памяти для объявлений и экземпляров объектов или для полного дерева вызовов.

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

На приведенном ниже экране показано использование оперативной памяти всеми объектами с указанием количества экземпляров:

./73dfc5ba09707a8f9bc41d1a60f197b8.png

JProfiler поддерживает интеграцию с популярными IDE , такими как Eclipse, NetBeans и IntelliJ. Можно даже перейти от моментального снимка к исходному коду !

3. Ваш комплект

YourKit Java Profiler работает на многих различных платформах и обеспечивает отдельные установки для каждой поддерживаемой операционной системы (Windows, MacOS, Linux, Solaris, FreeBSD и т. д.).

Как и JProfiler, YourKit имеет основные функции для визуализации потоков, сборки мусора, использования памяти и утечек памяти с поддержкой локального и удаленного профилирования через ssh-туннелирование .

Вот краткий обзор результатов профилирования памяти серверного приложения Tomcat:

./2cebfe2ccc42c94a953d179cf9955c96.png

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

YourKit имеет интересную функцию профилирования ЦП, которая позволяет сфокусировать профилирование на определенных областях нашего кода , таких как методы или поддеревья в потоках. Это очень мощное средство, поскольку оно позволяет выполнять условное профилирование с помощью функции «что, если».

На рис. 5 показан пример интерфейса профилирования потоков:

./ffff4616375a53def0040676dd8ce1fa.png

Мы также можем профилировать SQL и вызовы базы данных NoSQL с помощью YourKit. Он даже предоставляет представление для фактических запросов, которые были выполнены.

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

4. Визуальная виртуальная машина Java

Java VisualVM — это упрощенный, но надежный инструмент профилирования для приложений Java. По умолчанию этот инструмент входит в комплект Java Development Kit (JDK). Его работа зависит от других автономных инструментов, предоставляемых в JDK, таких как JConsole , jstat , jstack , jinfo и jmap .

Ниже мы видим простой обзорный интерфейс текущего сеанса профилирования с использованием Java VisualVM:

./c249a074ec5a6b1a207a7a88350f9929.png

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

Java VisualVM поддерживает локальное и удаленное профилирование , а также профилирование памяти и ЦП. Для подключения к удаленным приложениям требуется предоставление учетных данных (имя хоста/IP-адрес и пароль при необходимости) , но не предоставляется поддержка ssh-туннелирования . Мы также можем включить профилирование в реальном времени с мгновенными обновлениями (обычно каждые 2 секунды).

Ниже мы можем увидеть внешний вид памяти приложения Java, профилированного с помощью Java VisualVM:

./1485593bea1cc6c3746fe14ed9e4914f.png

Благодаря функции моментальных снимков Java VisualVM мы можем делать моментальные снимки сеансов профилирования для последующего анализа .

5. Профилировщик NetBeans

NetBeans Profiler входит в состав среды IDE Oracle NetBeans с открытым исходным кодом .

Хотя этот профилировщик во многом похож на Java VisualVM , это хороший выбор, когда мы хотим, чтобы все было упаковано в одну программу (IDE + Profiler).

Все другие профилировщики, рассмотренные выше, предоставляют плагины для улучшения интеграции с IDE.

На снимке экрана ниже показан пример интерфейса NetBeans Profiler:

./d930443a45dd7d26f8be7d69a846d4d2.png

Netbeans Profiler также является хорошим выбором для упрощенной разработки и профилирования . NetBeans Profiler предоставляет единое окно для настройки и управления сеансом профилирования и отображения результатов. Это дает уникальную возможность узнать , как часто происходит сборка мусора .

6. Другие профилировщики твердых тел

Некоторые почетные упоминания здесь — это Java Mission Control , New Relic и Prefix (от Stackify ) — они имеют меньшую долю рынка в целом, но, безусловно, заслуживают упоминания. Например, Stackify Prefix — отличный легкий инструмент профилирования, хорошо подходящий для профилирования не только Java-приложений, но и других веб-приложений.

7. Заключение

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

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

Jprofiler как пользоваться

JProfiler Help

IDE Integrations

When you profile your application, the methods and classes that come up in JProfiler’s views often lead to questions that can only be answered by looking their source code. While JProfiler provides a built-in source code viewer for that purpose, it has limited functionality. Also, when a problem is found, the next move is usually to edit the offending code. Ideally, there should be a direct path from the profiling views in JProfiler to the IDE, so you can inspect and improve code without any manual lookups.

Installing IDE integrations

JProfiler offers IDE integrations for IntelliJ IDEA, eclipse and NetBeans. To install an IDE plugin, invoke Session->IDE Integrations from the main menu. The plugin installation for IntelliJ IDEA is performed with the plugin management in the IDE, for other IDEs the plugin is installed directly be JProfiler. The installer also offers this action to make it easy to update the IDE plugin along with the JProfiler installation. The integration wizard connects the plugin with the current installation directory of JProfiler. In the IDE plugin settings, you can change the used version of JProfiler at any time. The protocol between the plugin and the JProfiler GUI is backwards compatible and can work with older versions of JProfiler as well.

The IntelliJ IDEA integration can also be installed from the plugin manager. In that case, the plugin will ask you for the location of the JProfiler executable when you profile for the first time.

On different platforms, the JProfiler executable is located in different directories. On Windows, it’s  bin\jprofiler.exe , on Linux or Unix  bin/jprofiler and on macOS there is a special helper shell script  Contents/Resources/app/bin/macos/jprofiler.sh in the JProfiler application bundle for the IDE integrations.

Source code navigation

Everywhere a class name or a method name is shown in JProfiler, the context menu contains a Show Source action.

If the session was not started from the IDE, the built-in source code viewer is shown that utilizes line number tables in the compiled class files to find methods. A source file can only be found if its root directory or a containing ZIP file is configured in the application settings

Together with the source code display, a bytecode viewer based on the jclasslib bytecode viewer shows the structure of the compiled class file.

If the session is launched from the IDE, the integrated source code viewer is not used and the Show Source action defers to the IDE plugin. The IDE integrations support launched profiling sessions, opening saved snapshots as well as attaching to running JVMs.

For live profiling sessions, you start the profiled application for the IDE similarly to running or debugging it. The JProfiler plugin will then insert the VM parameter for profiling and connect a JProfiler window to it. JProfiler is running as a separate process and is started by the plugin if required. Source code navigation requests from JProfiler are sent to the associated project in the IDE. JProfiler and the IDE plugin cooperate to make window switching seamless without blinking task bar entries, just as if you were dealing with a single process.

When starting the session, the «Session startup» dialog lets you configure all profiling settings. The configured profiling settings that are used for a launched session are remembered by JProfiler on a per-project or on a per-run-configuration basis, depending on the IDE integrations. When a session is profiled for the first time, the IDE plugin automatically determines a list of profiled packages based on the topmost classes in the package hierarchy of your source files. At any later point, you can go to the filter settings step in the session settings dialog and use the reset button to perform this calculation again.

For snapshots, the IDE integration is set up by opening a snapshot file from within the IDE with the File->Open action or by double-clicking on it in the project window. Source code navigation from JProfiler will then be directed into the current project. Finally, the IDE plugin adds an Attach to JVM action to the IDE that lets you select a running JVM and get source code navigation into the IDE, similar to the mechanism for snapshots.

Sometimes you may want to switch to the IDE without a particular class or method in mind. For that purpose, the tool bar in the JProfiler window has an Activate IDE button that is shown for profiling sessions that are opened by an IDE integration. The action is bound to the F11 key, just like the JProfiler activation action in the IDE, so you can switch back and forth between the IDE and JProfiler with the same key binding.

IntelliJ IDEA integration

To profile your application from IntelliJ IDEA, choose one of the profiling commands in the Run menu, the context menu in the editor, or click on the corresponding toolbar button.

JProfiler can profile most run configuration types from IDEA, including application servers. To configure further settings, edit the run configuration, choose the Startup/Connection tab, and select the JProfiler entry. The screen shot below shows the startup settings for a local server configuration. Depending on the run configuration type, you can adjust JVM options or retrieve profiling parameters for remote profiling.

The profiled application is then started just as with the usual «Run» commands. Precise source code navigation is implemented for Java and Kotlin.

On the JProfiler tab of the IDE settings, you can adjust the used JProfiler executable and whether you always want to open a new window in JProfiler for new profiling sessions.

The JProfiler tool window in IDEA is shown when you profile a run configuration from IDEA, when you open a JProfiler snapshot or when you attach to a running JVM.

The action in the tool bar with the JProfiler icon activates the JProfiler window. On the right side of the tool bar, several toggle buttons give access to important recording actions in JProfiler. If a recording is active, the corresponding toggle button is selected.

Of particular relevance is the CPU recording action, because CPU graph data can be shown directly in the IDE. The only parameter for graph calculation that is offered in the IDE is the thread status. To configure advanced parameters like thread selection or to use the call tree root, call tree removal and call tree view filter settings from the call tree view, you can generate the graph in the JProfiler window, it will then be shown in the IDE as well.

When you calculate a graph, the list of hot spots will be populated and the source code will be annotated with gutter icons for incoming and outgoing calls. The popup on the gutter icons shows an inline graph, clicking on a method will navigate to it. The list of hot spots shows you interesting entry points for analyzing the graph. When double-clicking on a table row, the source code is shown.

The Show in JProfiler button contains actions that activate the JProfiler window, either the selected node in the method graph or the corresponding call tree analysis in the method graph. For outgoing calls, the «Cumulated outgoing calls» analysis is offered, for the incoming calls, the «Backtraces» analysis is shown. All these actions are also available in the context menu of the hot spot list or as keyboard actions.

eclipse integration

The eclipse plugin can profile most common launch configuration types including test run configurations and WTP run configurations. The eclipse plugin only works with the full eclipse SDKs and not with partial installations of the eclipse framework.

To profile your application from eclipse, choose one of the profiling commands in the Run menu or click on the corresponding toolbar button. The profile commands are equivalent to the debug and run commands in eclipse and are part of eclipse’s infrastructure, except for the Run->Attach JProfiler to JVM menu item which is added by the JProfiler plugin.

If the menu item Run->Profile . does not exist in the Java perspective, enable the «Profile» actions for this perspective under Window->Perspective->Customize Perspective by bringing the Action Set Availability tab to front and selecting the Profile checkbox.

Several JProfiler-related settings including the location of the JProfiler executable can be adjusted in eclipse under Window->Preferences->JProfiler.

NetBeans integration

In NetBeans, you can profile standard, free form and Maven projects that use the exec Maven plugin. To profile your application from NetBeans, choose one of the profiling commands in the Run menu or click on the corresponding toolbar button. For Maven projects that start an application in another way and for Gradle projects, start the project normally and use the Profile->Attach JProfiler To A Running JVM action in the menu.

For free form projects, you have to debug your application once before trying to profile it, because the required file nbproject/ide-targets.xml is set up by the debug action. JProfiler will add a target named «profile-jprofiler» to it with the same contents as the debug target and will try to modify the VM parameters as needed. If you have problems profiling a free form project, check the implementation of this target.

You can profile web applications with the integrated Tomcat or with any other Tomcat server configured in NetBeans. When your main project is a web project, selecting Profile main project with JProfiler starts the Tomcat server with profiling enabled.

If you use NetBeans with the bundled GlassFish Server and your main project is set up to use a GlassFish Server, selecting Profile main project with JProfiler starts the application server with profiling enabled.

The location of the JProfiler executable and the policy for opening new JProfiler windows can be adjusted under Miscellaneous->JProfiler in the options dialog.

Используем JProfiler для анализа производительности кода

RSS

JProfiler является классом для анализа производительности вашего кода. Он позволяет проследить следующее:

Application Start: 0.000 seconds, 0.10 MB
\_______/ \___/ \__________/ \_____/
. | | | |
. prefix label time memory

  • prefix — служит в качестве идентификатора для отдельных объектов JProfiler (см. ниже);
  • label — название метки производительности;
  • time — время от создания объекта JProfiler до установленной метки;
  • memory — память, выделеямая Вашему скрипту в тот момент, когда устанавливается метка производительности.

Класс JProfiler обеспечивает метод GetInstance , который мы можем назвать статическим. Он служит для организации глобальной точки доступа отдельных объектов JProfiler. Он сохраняет массив созданных объектов и предоставляет доступ к ним на основании префиксов, которые могут быть предоставлены в качестве аргумента. Кроме того, если объект с требуемым префиксом отсутствует, то метод GetInstance создаст его.

jimport( 'joomla.error.profiler' );
$p = JProfiler::getInstance( ); 

$p->mark('Start');
$a = str_repeat("hello world!\n", 100000);
$p->mark('Middle');
unset($a);
$p->mark('Stop');

print_r($p->getBuffer());

Резултьтат этого кода будет примерно следующий:

Array ( 
[0] => Start: 0.000 seconds, 3.87 MB
[1] => Middle: 0.002 seconds, 5.11 MB
[2] => Stop: 0.002 seconds, 3.87 MB
)

Так же можно использовать использовать следующий метод

$p = JProfiler::getInstance('Application');

Результат будет в виде массива:

Array ( 
[0] => Application afterLoad: 0.005 seconds, 0.27 MB
[1] => Application afterInitialise: 0.163 seconds, 2.55 MB
[2] => Application afterRoute: 0.196 seconds, 3.09 MB
[3] => Application Start: 0.253 seconds, 3.87 MB
[4] => Application Middle: 0.255 seconds, 5.11 MB
[5] => Application Stop: 0.255 seconds, 3.87 MB
)

Т.е. грубо говоря, можно использовать этот класс для установки меток в нужном нам месте и в дальнейшем оценить производительность кода.

В поисках перформанса, часть 2: Профилирование Java под Linux

Бытует мнение, что бесконечно можно смотреть на огонь, воду и то, как другие работают, но есть и ещё кое-что! Мы уверены, что можно бесконечно говорить с Сашей goldshtn Гольдштейном о перформансе. Мы уже брали у Саши интервью перед JPoint 2017, но тогда разговор касался конкретно BPF, которому был посвящен доклад Саши.

На этот раз мы решили копнуть глубже и узнать фундаментальные проблемы мониторинга производительности и варианты их решения.

С чего стоит начинать

— В прошлый раз мы довольно подробно поговорили про BPF и вскользь обсудили проблемы мониторинга производительности Java под Linux. В этот раз хотелось бы сконцентрироваться не на конкретном инструменте, а на проблемах и поиске решений. Первый вопрос, довольно банальный, — как понять, что с производительностью есть проблемы? Следует ли думать об этом, если пользователь не жалуется?

Саша Гольдштейн: Если начинать думать о производительности только в момент, когда ваши пользователи жалуются, с вами они будут недолго. Для многих инженерия производительности — это траблшутинг и crisis mode. Телефоны звонят, свет мигает, система упала, клавиатура горит — обычные трудовый будни перформанс-инженера. В реальности же они проводят большую часть своего времени, планируя, проектируя, мониторя и предотвращая кризисы.

Для начала, capacity planning — оценка ожидаемой нагрузки системы и использования ресурсов; проектирование масштабируемости поможет избежать узких мест и получить значительные увеличения в нагрузке; инструментирование и мониторинг жизненно необходимы для понимания того, что происходит внутри системы, чтобы не копаться вслепую; благодаря установке автоматического оповещения вы точно будете знать о любых возникающих проблемах, как правило ещё до того, как пользователи начнут жаловаться; ну и конечно же будут единичные кризисы, решать которые придётся в стрессовых условиях.

Стоит отметить, что тулы постоянно меняются, но сам процесс остаётся неизменным. Приведу пару конкретных примеров: capacity planning вы можете сделать и на бумажке на коленке; можно использовать APM-решения (как New Relic или Plumbr) для end-to-end инструментирования и мониторинга, AB и JMeter для быстрого нагрузочного тестирования и так далее. Чтобы узнать больше, можно почитать книгу Брендана Грегга «Systems Performance» — это отличный источник по теме жизненного цикла и методологии перформанса, а «Site Reliability Engineering» от Google освещает тему установки характеристик производительности (Service Level Objectives) и их мониторинга.

— Допустим, мы поняли, что проблема есть: с чего начинать? Мне часто кажется, что многие (особенно не профессиональные перформанс-инженеры) сразу готовы расчехлять JMH, переписывать всё на unsafe и «хакать компиляторы». Потом смотреть, что получилось. Но ведь в реальности лучше не с этого начинать?

Саша Гольдштейн: Это довольно распространённая практика, когда при написании кода и проведении базовых тестов профайлера возникают проблемы с перформансом, которые можно легко исправить, поменяв код или «хакнув компиляторы». Однако на проде, исходя из моего опыта, это делается не так часто. Многие проблемы присущи только какой-то одной среде, вызваны меняющимися паттернами рабочей нагрузки или связаны с узкими местами вне кода вашего приложения, и лишь малую часть можно замикробенчмаркать и улучшить на уровне исходного кода «умными» хаками.

Вот пара примеров для иллюстрации:

  • Пару лет назад Datadog столкнулись с проблемой, когда вставки и обновления базы данных в PostgreSQL скакали от 50 мс до 800 мс. Они использовали AWS EBS с SSD. Что это дало? Вместо тюнинга базы данных или изменения кода приложения они обнаружили, что виноват во всём троттлинг EBS: у него есть квота по IOPS, в случае превышения которой вы попадёте под ограничение производительности.
  • Недавно у меня был пользователь с проблемой огромных скачков времени отклика на сервере, которые были связаны с задержками сбора мусора. Некоторые запросы занимали более 5 секунд (и появлялись они абсолютно бессистемно), так как сборка мусора выходила из-под контроля. Внимательно изучив систему, мы обнаружили, что с распределением памяти приложения или же с тюнингом сборки мусора всё было в порядке; из-за скачка в размере рабочей нагрузки фактическое использование памяти повысилось и вызвало свопинг, что абсолютно губительно для реализации любой сборки мусора (если сборщику нужно подкачивать и откачивать память, чтобы отмечать активные объекты, — это конец).
  • Пару месяцев назад Sysdig столкнулся с проблемой изоляции контейнера: находясь рядом с контейнером Х, операции с файловой системой, выполняемые контейнером Y, были гораздо медленнее, в то время как использование памяти и загрузка процессора для обоих контейнеров были очень низкими. После небольшого исследования они обнаружили, что кэш каталогов ядра перегружался контейнером Х, что в дальнейшем вызывало коллизию хэш-таблицы и, как следствие, значительное замедление. Опять-таки, изменение кода приложения или распределения ресурсов контейнера эту проблему бы не решили.

— Наверняка следует сначала посмотреть, как приложение/сервис работает в продакшне. Какие инструменты ты для этого рекомендуешь, а какие — не очень?

Саша Гольдштейн: Мониторинг и профайлинг на проде — это набор инструментов и техник.

Начинаем с метрик высокоуровневого перформанса, фокусируясь на использовании ресурсов (процессор, память, диск, сеть) и характеристике нагрузки (# запросов, ошибок, типов запросов, # запросы к базе данных). Есть стандартные тулы для получения этих данных для каждой операции и времени выполнения. К примеру, на Linux обычно используют инструменты вроде vmstat, iostat, sar, ifconfig, pidstat; для JVM используют JMX-based тулы или jstat. Это метрики, которые можно непрерывно собирать в базу данных, возможно с 5-ти или 30-ти секундным интервалом, чтобы можно было проанализировать скачки и при необходимости вернуться в прошлое, чтобы скоррелировать предыдущие операции по развёртыванию, релизы, мировые события или изменения рабочей нагрузки. Важно, что многие фокусируются на собирании только средних показателей; они хоть и хороши, но, по определению, не представляют полное распределение того, что вы измеряете. Гораздо лучше собирать процентили, а по возможности даже и гистограммы.

Следующий уровень — это операционные метрики, которые обычно нельзя непрерывно собирать или хранить долгое время. Они включают в себя: лог сбора мусора, запросы сети, запросы к базе данных, классовые нагрузки и так далее. Разобраться в этих данных после того, как их где-то хранили, иногда гораздо труднее, чем, собственно, их собирать. Это позволяет, однако, задавать вопросы, вроде «какие запросы работали, пока нагрузка ЦП базы данных повышалась до 100%» или «какими были IOPS дисков и время отклика во время выполнения этого запроса». Одни лишь числа, особенно в виде средних показателей, не позволят вам провести подобного рода исследование.

И наконец, «хардкорный» уровень: SSH в сервере (или удаленный запуск тулов) для сбора большего количества внутренних метрик, которые нельзя хранить во время штатной работы сервиса. Это инструменты, которые обычно называют «профайлерами».

Для профайлинга Java-продакшна существует множество жутких тулов, которые не только дают большой оверхэд и задержки, но могут ещё и лгать вам. Несмотря на то, что экосистеме уже около 20 лет, есть лишь несколько надёжных профайлинговых техник с низким оверхэдом для JVM-приложений. Я могу порекомендовать Honest Profiler Ричарда Ворбертона, async-profiler Андрея Паньгина и, конечно, моего любимчика — perf.

Кстати, много тулов фокусируются на профайлинге процессора, разбираясь в том, какой путь выполнения кода вызывает высокую загрузку ЦП. Это здорово, но часто проблема не в этом; нужны инструменты, которые могут показывать пути выполнения кода, ответственные за распределение памяти (async-profiler теперь может делать и это), ошибки отсутствия страницы, непопадание в кэш, доступы к диску, запросы сети, запросы к базе данных и другие события. Меня в этой области привлекла именно проблема поиска правильных перформанс-тулов для исследования работающей среды.

Профилирование Java под Linux

— Я слышал, что под Java/Linux стек есть куча проблем с достоверностью замеров. Наверняка с этим можно как-то бороться. Как ты это делаешь?

Саша Гольдштейн: Да, это печально. Вот как выглядит текущая ситуация: у вас есть быстрая конвейерная линия с огромным количеством разных частей, которые нужно протестировать, чтобы найти дефекты и понять скорость приложения/сервиса. Вы не можете проверить абсолютно каждую часть, поэтому ваша основная стратегия — это проверять 1 часть в секунду и смотреть, всё ли в порядке, и вам нужно это делать через «крохотное окно» над этой «лентой», потому что подходить ближе уже опасно. Вроде неплохо, не так ли? Но потом оказывается, что когда вы пытаетесь в него посмотреть, оно показывает вам не то, что происходит на конвейере прямо сейчас; оно ждёт, пока конвейер перейдёт в волшебный «безопасный» режим, и только после этого даёт вам всё увидеть. Также оказывается, что многих частей вы не увидите никогда, потому что конвейер не может войти в свой «безопасный» режим, пока они рядом; и ещё оказывается, что процесс поиска дефекта в окошке занимает целых 5 секунд, так что делать это каждую секунду невозможно.

Примерно в таком состоянии сейчас находится множество профайлеров в мире JVM. YourKit, jstack, JProfiler, VisualVM — у всех у них одинаковый подход к профайлингу ЦП: они используют семплинг потоков в безопасном состоянии. Это значит, что они используют документированный API, чтобы приостановить все JVM-треды и взять их стек-трейсы, которые затем собирают для отчёта с самыми горячими методами и стеками.

Проблема такой приостановки процесса заключается в следующем: треды не останавливаются сразу же, рантайм ждёт, пока они не дойдут до безопасного состояния, которое может находиться после множества инструкций и даже методов. В результате вы получаете необъективную картину работы приложения, а разные профайлеры могут ещё и не соглашаться друг с другом!

Есть исследование, показывающее, насколько это плохо, когда у каждого профайлера своя точка зрения по поводу самого горячего метода в одной и той же рабочей нагрузке (Миткович и соавт., «Evaluating the Accuracy of Java Profilers»). Более того, если у вас есть 1000 тредов в сложном стеке вызовов Spring, часто собирать стек-трейсы не получится. Возможно, не чаще 10 раз в секунду. В результате ваши данные по стекам будут отличаться от фактической рабочей нагрузки ещё больше!

Решать такие проблемы непросто, но вкладываться стоит: некоторые рабочие нагрузки на проде невозможно профилировать, используя «традиционные» тулы вроде перечисленных выше.

Существует два раздельных подхода и один гибридный:

  • Honest Profiler Ричарда Ворбертона использует внутренний недокументированный API, AsyncGetCallTrace, который возвращает стек-трейс одного треда, не требует перехода в безопасное состояние и вызывается с помощью обработчика сигнала. Изначально он был спроектирован Oracle Developer Studio. Основной подход заключается в установке обработчика сигнала и его регистрации на сигнал с установленным временем (например, 100 Гц). Затем необходимо взять стек-трейс любого треда, который в данный момент работает внутри обработчика сигнала. Очевидно, что есть непростые задачи, когда дело доходит до эффективного объединения стек-трейсов, особенно в контексте обработчика сигнала, но этот подход отлично работает. (Этот подход использует JFR, требующий коммерческую лицензию)
  • Linux perf может предоставлять богатый сэмплинг стеков (не только для инструкций ЦП, но и для других событий, таких как доступ диска и запросы сети). Проблема заключается в преобразовании адреса Java-метода в имя метода, что требует наличие JVMTI-агента, достающего текстовый файл (perf map), который perf может читать и использовать. Есть также проблемы с реконструкцией стека, если JIT использует подавление указателей фрейма. Этот подход вполне может работать, но требует небольшой подготовки. В результате, однако, вы получите стек-трейсы не только для JVM-тредов и Java-методов, но и для всех имеющихся у вас тредов, включая стек ядра и стеки C++.
  • async-profiler Андрея Паньгина сочетает в себе два подхода. Он устанавливает набор образцов perf, но также использует обработчик сигнала для вызова AsyncGetStackTrace и получения Java-стека. Объединение двух стеков даёт полную картину того, что происходит в потоке, позволяя избегать проблем с преобразованием имен Java-методов и подавлением указателей фрейма.

Профилирование в контейнерах

— К слову об окружениях, сейчас модно всё паковать в контейнеры, здесь есть какие-то особенности? О чём следует помнить, работая с контейнеризованными приложениями?

Саша Гольдштейн: С контейнерами возникают интересные проблемы, которые многие тулы полностью игнорируют и в результате вообще перестают работать.

Вкратце напомню, что контейнеры Linux построены вокруг двух ключевых технологий: группы контроля и пространства имён. Группы контроля позволяют увеличить квоту ресурсов для процесса или для группы процессов: CPU time caps, лимит памяти, IOPS хранилища и так далее. Пространства имён делают возможной изоляцию контейнера: mount namespace предоставляет каждому контейнеру свою собственную точку монтирования (фактически, отдельную файловую систему), PID namespace — собственные идентификаторы процессов, network namespace даёт каждому контейнеру собственный сетевой интерфейс и так далее. Из-за пространства имён множеству тулов сложно правильно обмениваться данными с контейнезированными JVM-приложениями (хотя некоторые из этих проблем свойственны не только JVM).

Прежде чем обсудить конкретные вопросы, будет лучше, если мы вкратце расскажем о разных видах observability тулов для JVM. Если вы не слышали о некоторых из них, самое время освежить ваши знания:

  • базовые тулы вроде jps и jinfo предоставляют информацию о действующих JVM-процессах и их конфигурации;
  • jstack можно использовать, чтобы достать thread dump (стек-трейс) из действующих JVM-процессов;
  • jmap — для получения head dump действующих JVM-процессов или более простых гистограмм классов;
  • jcmd используется, чтобы заменить все предыдущие тулы и отправить команды действующим JVM-процессам через JVM attach interface; он основан на сокете домена UNIX, который используется JVM-процессами и jcmd для обмена данными;
  • jstat — для мониторинга базовой информации JVM-перформанса, как загрузка класса, JIT-компиляция и статистика сборки мусора; основан на JVM, генерирующей файлы /tmp/hsperfdata_$UID/$PID с этими данными в бинарном формате;
  • Serviceability Agent предоставляет интерфейс для проверки памяти JVM процессов, тредов, стеков и так далее и может быть использован с дампом памяти и не только живых процессов; он работает, читая память процесса и структуры внутренних данных;
  • JMX (управляемые бины) может использоваться для получения информации о перформансе от действующего процесса, а также для отправления команд, чтобы контролировать его поведение;
  • JVMTI-агенты могут присоединяться к разным интересным JVM-событиям, таким как загрузка классов, компиляция методов, запуск/остановка треда, monitor contention и так далее.
  • большинство инструментов требуют доступ к бинарникам процесса для поиска объектов и значений. Всё это находится в mount namespace контейнера и недоступно из хоста. Частично этот доступ можно обеспечить при помощи bind-mounting из контейнера или к вводу mount namespace контейнера в профайлере во время выполнения symbol resolving (это то, что сейчас делают perf и BCC тулы, о которых я рассказывал в предыдущем интервью).
  • если у вас есть JVMTI-агент, который генерирует perf map (например, perf-map-agent), она будет написана в хранилище контейнера /tmp, используя ID процесса контейнера (например, /tmp/perf-1.map). Map-файл должен быть доступен хосту, а хост должен ждать верный ID процесса в имени файла. (Опять же, perf и BCC теперь могут делать это автоматически).
  • JVM attach interface (на который полагаются jcmd, jinfo, jstack и некоторые другие тулы) требует верных PID и mount namespace attach файла, а также сокет UNIX домена, использовавшегося для обмена данными с JVM. Эту информацию можно прокинуть при помощи jattach utility и создания attach файла, входя в пространство имён контейнера или при помощи bind-mounting соответствующих директорий на хосте.
  • использование файлов данных о производительности JVM (в /tmp/hsperfdata_$UID/$PID), которыми пользуется jstat, требует доступ к монтированию пространства имён контейнера. Это легко адресуется bind-монтированием /tmp контейнера на хосте;
  • самый простой подход к использованию JMX-based инструментов — это, пожалуй, доступ к JVM, как если бы она была удалённой — конфигурируя RMI endpoint, как вы бы делали для удалённой диагностики;
  • тулы Serviceability Agent требуют точного соответствия версий между JVM-процессом и хостом. Думаю, вы понимаете, что не стоит запускать их на хосте, особенно если он использует разное распределение и на нём установлены разные версии JVM.

Мы хотели продолжить разговор и обсудить влияние железа на профилирование…

Совсем скоро Саша приедет в Санкт-Петербург, чтобы провести тренинг по профилированию JVM-приложений в продакшне и выступить на конференции Joker 2017 с докладом про BPF, поэтому, если вы хотите погрузиться в тему глубже – у вас есть все шансы встретиться с Сашей лично.

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

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