JDK Flight Recorder — тайное оружие OpenJDK
JDK Flight Recorder, или Java Flight Recorder (JFR) — это инструмент Hotspot JVM. JFR впервые появился в JRockit JVM и, начиная с Oracle Java 7, был перенесён в Hotspot JVM. Во время выхода Java 9 исходный код JFR был открыт, а теперь это часть OpenJDK.
В этой статье я выделю ключевые особенности Java Flight Recorder и объясню, чем он может быть полезен для разработчиков Java.
Оглавление:
- Что такое JDK Flight Recorder?
- Что такое Mission Control?
- Java Flight Recorder — это ещё один профилировщик Java?
- Как начать пользоваться Java Flight Recorder?
- Краткое содержание отчётов Mission Control
- Непрерывное профилирование
Что такое JDK Flight Recorder?
Java Flight Recorder — это инструмент диагностики и мониторинга производительности, который экономит время Java-инженеров при устранении неполадок в приложениях во время выполнения. Java Flight Recorder собирает различные виды событий во время работы Java-приложения и записывает их в виде бинарных лог-файлов (англ. recordings, далее называемых записями). В OpenJDK 11 JFR может отслеживать несколько сотен типов событий, показывая детальную картину времени выполнения JVM. Записи, создаваемые JFR, представляют собой самодостаточные файлы, которые могут быть проанализированы в Mission Control.
Что такое Mission Control?
Mission Control — это графический интерфейс для работы с записями Java Flight Recorder. Mission Control имеет открытый исходный код, размещённый на GitHub.
Запись JFR — обычная коллекция событий. Чтобы эти данные обрели смысл, их нужно обработать. Mission Control предлагает несколько встроенных отчётов, описывающих различные аспекты времени выполнения JVM, такие как выполнение кода, распределение объектов, сборка мусора и другие. Помимо общих отчётов, у Mission Control есть ряд эвристик для выявления типичных проблем Java-приложений. Чтобы настроить отчёты, подходящие именно для вашей задачи, используйте браузер событий и настраиваемые фильтры.
Java Flight Recorder — это ещё один профилировщик Java?
Функции JFR в паре с Mission Control частично пересекаются с возможностями профилировщиков, но их прямое сравнение не совсем корректно. JFR — уникальный инструмент JDK, который могут использовать и другие профилировщики, помимо Mission Control.
Для таких задач, как выявление горячих участков кода или анализ выделения объектов, JFR + Mission Control схож с типичным профилировщиком, таким как VisualVM. Это хороший Java-профилировщик с открытым исходным кодом, который вы можете использовать вместо платных коммерческих инструментов.
Некоторые функции, характерные для профилировщиков, отсутствуют в JFR. Например, отслеживание SQL-запросов к базе данных.
Вы можете отправлять в JFR события, специфичные для конкретного приложения. Для этого сначала нужно добавить генерацию событий в логику приложения.
Некоторые виды телеметрии JVM доступны только в JFR.
Как начать пользоваться Java Flight Recorder?
JFR встроен в OpenJDK. Чтобы начать пользоваться JFR, вам не нужно устанавливать что-то помимо JDK или как-то настраивать JVM.
Open JDK 11 — первый релиз LTS (Long Term Support) с встроенным JFR.
Если у вас ещё нет JDK с поддержкой JFR, установите версию, соответствующую вашей ОС и архитектуре CPU из Центра загрузок Axiom JDK. Axiom JDK Pro — бинарный дистрибутив с открытым исходным кодом и поддержкой от компании-поставщика российской платформы Java. Axiom JDK Pro поддерживает много платформ, что делает его универсальной средой исполнения Java для облачных вычислений, серверов и десктопных систем.
Работа с JFR выглядит следующим образом:
- Запустите запись событий во время выполнения приложения с заданной конфигурацией.
- После активности сессии в течение достаточного времени, сбросьте данные записи в файл.
- После выгрузки логов в файл, остановите запись. Если вы планируете дальше выгружать логи в файл, то оставьте сессию активной.
Есть три способа включить запись событий:
- Используя jcmd — инструмент CLI, входящий в состав JDK. С jcmd вы можете запустить, остановить или сбросить сеансы JFR. Чтобы использовать jcmd,вам потребуется доступ к командной строке сервера, на котором запущено ваше Java-приложение.
- Используя Mission Control. Это подходит как для локально запущенных процессов, так и для процессов, выполняющихся удаленно. Для удаленного подключения к JVM понадобится настроенный JMX.
- При старте приложения c помощью параметров командной строки. Этот способ удобен, если вы хотите анализировать поведение приложения во время запуска.
Для старта записи требуется конфигурация (также называемая профилем). Профиль определяет, какие типы событий будут собираться во время сеанса. Он также определяет конфигурацию для проб: частоту выборки методов, порог длительности для событий ввода/вывода и другие.
Есть два встроенных профиля: по умолчанию (default) и профилирование (profiling). Вы также можете настраивать и использовать собственные профили через пользовательский интерфейс Mission Control.
Когда у вас появится файл записи JFR, вам понадобится Mission Control, чтобы открыть его. Mission Control доступен вместе со сборками Axiom JDK.
Краткое содержание отчётов Mission Control
Mission Control имеет множество функций и довольно сложен в освоении. В Java 8 от Oracle в комплекте с JDK поставлялась версия Mission Control 5.5 с закрытым исходным кодом.
Mission Control 6 поставлялся в комплекте с JDK 9. Это было кардинальное обновление, в частности из-за открытого доступа к кодовой базе. В этой же версии Mission Control 6 появилось автоматическое обнаружение аномалий. Подсказки, выдаваемые эвристиками, могут быть очень полезны для новичков. Однако рано или поздно придётся погрузиться и в другие отчёты.
Mission Control 8 является самой последней версией. Он может анализировать записи от JDK 7+. Для запуска JMC вам потребуется JDK 11+.
Далее я хотел бы дать краткое описание основных отчётов, доступных в Mission Control.
Профилирование методов (Method profiling)
JFR может периодически делать снимки стека запущенных потоков в JVM. Эта техника известна как профилирование сэмплированием и доступна во всех профилировщиках Java. Статистический анализ большого массива снимков показывает, где приложение проводит большую часть времени, с точностью до имени метода или даже номера строки. Этот отчёт предоставляет полезную визуализацию для такого подмножества данных, собранных JFR.
Профилирование сэмплированием используется в случае, когда производительность приложения упирается в производительность процессора. Этот метод помогает выявить неэффективный код, который можно оптимизировать, чтобы повысить производительность.
Память (Memory)
Этот отчёт описывает историю использования памяти вашим Java-приложением. Отчёт объединяет несколько разделов данных, наиболее важный из которых — сэмплирование выделения памяти под объекты.
Если JFR включен, он записывает события выделения памяти для объектов, включая выделяемый класс, размер объекта и снимки стека до точки выделения памяти. Статистический анализ этой выборки может многое рассказать о вашем коде.
Отчёты Memory показывают типы объектов, память под которые наиболее часто выделяется в куче. Вы также увидите информацию о фактическом объёме выделенной памяти, включая стек вызовов до точки в коде, выполнившей выделение.
Если вы хотите снизить нагрузку на сборщик мусора или оптимизировать использование памяти, то посмотрите этот отчёт. Профилирование памяти ценно тогда, когда оно помогает быстро выявить “мусорящий” код приложения и подать идею, где можно его оптимизировать.
Lock Instances
Конкуренции между потоками и взаимные блокировки — ещё один класс проблем Java, к которым сложно подступиться без хорошего инструмента. JFR собирает события блокировки потоков на synchronized-секциях и других примитивах синхронизации, что может быть полезно при исследовании проблем параллельного исполнения в Java.
Отчёт Lock Instances покажет вам сводную статистику по этим событиям. Отчёт Threads — это ещё один способ отслеживания проблем с параллельным исполнением.
Встроенная конфигурации Profiling имеет минимальный порог длительности для записи таких событий. Вам может потребоваться его снизить, чтобы получить более детальную картину.
Издержки межпоточных блокировок становятся жестокой реальностью для кода, использующего большое количество потоков и работающего на десятках ядер. Java поставляется с несколькими примитивами координации работы потоков, включая неблокирующие. Отчёт о блокировках помогает понять стоимость многопоточности в вашем приложении и выявить узкие места, где переход на более эффективный метод взаимодействия между потоками будет наиболее выгодным.
File I/O and Socket I/O
JFR также отслеживает операции ввода-вывода для файлов и сокетов. В этих отчётах отображается сводная статистика, построенная на основе событий ввода-вывода для файлов и сокетов соответственно.
Интересно увидеть, какие файлы и как долго читало ваше приложение или с какими удалёнными узлами оно обменивалось данными.
Правда есть один нюанс. При первом использовании JFR вы можете обнаружить, что оба этих отчёта пусты или почти пусты. Причина — порог в 10 мс, используемый по умолчанию для такого рода событий. Если вы хотите увидеть полную картину ввода-вывода, установите значение порога равное нулю при запуске записи событий.
Используйте этот отчёт для отлова “неожиданных” событий ввода-вывода, спрятанных глубоко внутри библиотек и фреймворков.
Threads
В этом отчёте вы увидите различные события, связанные с конкуренцией за совместно используемые ресурсы, вводом-выводом, изменением состояния Java-потока на единой шкале времени. Вы можете наблюдать взаимодействие потоков в интуитивно понятной форме. Также полезна возможность масштабирования с точностью до миллисекунды.
Exceptions
Каждое Java-приложение во время работы регулярно бросает те или иные исключения. Некоторые из них попадают в логи, но многие теряются внутри приложения. Это приводит к потраченным на поиск причины часам в случае возникновения каких-либо проблем.
JFR показывает все исключения, независимо от того, были ли они обработаны приложением или нет. По умолчанию, JFR показывает общее количество исключений, что помогает в случае неправильного использования исключений. Но, с помощью дополнительной настройки, можно записать каждое исключение вместе со стеком вызовов.
Garbage Collections
Решение проблем сборки мусора обычно включает в себя копание в логах GC. И, конечно же, у вас в продакшене правильно настроены логи сборки мусора, правда?
JFR собирает подробную информацию о событиях GC, которую вы можете увидеть в этом отчёте. Здесь вы можете увидеть практически любую метрику сборщика мусора, присутствующую в JVM.
Если вам нужно оптимизировать GC или устранить аномальные паузы в его работе, начните с этого отчёта.
Операции JVM
В HotSpot есть целый класс системные операции виртуальной машины Java. Все они требуют паузы Stop-the-World. С помощью некоторых опций JVM вы можете включить логирование VM-операций или использовать JFR и этот отчёт.
Системные операции JVM часто путают с паузами сборки мусора (которые являются лишь одним из возможных типов системных операций виртуальной машины). Люди склонны винить в Stop-the-World паузах сборщиков мусора. Если в вашем приложении есть паузы Stop-the-World, то начните с этого отчёта.
Настройки и окружение
Особенность файлов JFR в том, что вы можете отправить их на анализ эксперту в области JVM. В файлах содержится конфигурация JVM, конфигурация оборудования и даже список других процессов, запущенных на сервере и конкурирующих за ресурсы приложения. Будучи гуру JVM, я могу получить практически любую необходимую мне информацию из самого файла записи.
Непрерывное профилирование
Без сомнения, JFR в связке с Mission Control можно использовать как бесплатный и эффективный профилировщик Java. Но использование его в непрерывном режиме может принести ещё больше пользы.
Чтобы получить все преимущества от непрерывной записи событий во время выполнения приложения, вам нужно:
Настроить JVM так, чтобы она была доступна через JMX. Добавить аргументы командной строки JVM, чтобы активировать JFR при запуске.
Ниже приведена минимальная команда, чтобы запустить JFR:
java -XX:StartFlightRecording=name=background,maxsize=100m
Самая важная опция — maxsize
ограничивает количество событий, сохраняемых в памяти.
Теперь JFR тихо собирает события в фоновом режиме. Пока приложение работает нормально, вы можете забыть о работающем JFR. Профилирование JFR по умолчанию имеет малые накладные расходы.
Тем не менее, если дело примет дурной оборот, вы можете быстро подключиться к JVM через Mission Control и сбросить накопленные события с проблемного сервера. Это особенно полезно для отслеживания проблем, воспроизводимых только на продакшене.
Можно возразить, что вместо выгрузки данных с отдельных процессов лучше иметь централизованную систему мониторинга, в которой есть доступ к диагностике с любого сервера. В теории звучит хорошо, но на деле организовать качественный централизованный мониторинг крайне сложно. В решениях для централизованного мониторинга приходится идти на компромисс в детализации.
Непрерывная запись событий во время выполнения приложения и возможность выгружать события по требованию дополняют решения для централизованного логирования и общего мониторинга, поскольку вы можете получить очень подробную телеметрию от JVM.
Заключение
Java Flight Recorder — это зрелая технология, интегрированная в современный OpenJDK.
JFR в связке с Mission Control — надёжная альтернатива коммерческим Java-профилировщикам для большинства распространённых задач профилирования. Вы также можете использовать Java-профилировщики с открытым исходным кодом для решения таких задач.
JFR выходит за рамки простого профилировщика благодаря своей способности непрерывно собирать данные и иметь к ним удалённый доступ.
Будучи частью сборки JVM, Java Flight Recorder легко включается и не требует предварительной настройки, что делает его мощным инструментом в арсенале Java-инженера.
Итак, если у вас есть проблемы с производительностью или стабильностью Java, попробуйте Java Flight Recorder в паре с Mission Control.