Брюс Ву

Задний план

Диагностика производительности - это проблема, с которой инженеры-программисты должны часто сталкиваться и решать в своей повседневной работе. Сегодня взаимодействие с пользователем имеет первостепенное значение, и повышение производительности приложений может дать значительные преимущества. Java - один из самых популярных языков программирования. Его диагностика производительности долгое время привлекала большое внимание в отрасли. Многие факторы могут вызвать проблемы с производительностью в приложениях Java. К таким факторам относятся управление потоками, дисковый ввод-вывод, доступ к базе данных, сетевой ввод-вывод и сборка мусора (GC). Чтобы найти эти проблемы, вам понадобится отличный инструмент диагностики производительности. В этой статье описываются некоторые распространенные инструменты диагностики производительности Java, а также освещаются основные принципы и передовые методы работы с JProfiler, отличным представителем этих инструментов. Версия JProfiler, обсуждаемая в этой статье, - JProfiler10.1.4.

Краткое введение в инструменты диагностики производительности Java

В мире Java доступны различные инструменты диагностики производительности, включая простые инструменты командной строки, такие как jmap и jstat, и комплексные графические инструменты диагностики, такие как JVisualvm и JProfiler. В следующем разделе кратко описывается каждый из этих инструментов.

Простые инструменты командной строки

Java Development Kit (JDK) предлагает множество встроенных инструментов командной строки. Они могут помочь вам получить информацию о целевой виртуальной машине Java (JVM) с разных аспектов и на разных уровнях.

  • jinfo - позволяет просматривать и настраивать различные параметры целевой JVM в режиме реального времени.
  • jstack - позволяет получать информацию о стеке потоков целевого процесса Java, обнаруживать взаимоблокировки и определять местонахождение бесконечных циклов.
  • jmap - позволяет получать информацию, относящуюся к памяти целевого процесса Java, включая использование различных куч Java, статистическую информацию об объектах в кучах Java и загруженных классах.
  • jstat - легкий универсальный инструмент мониторинга. Он позволяет получать различную информацию о загруженных классах, JIT-компиляции, сборке мусора и использовании памяти целевым процессом Java.
  • jcmd - более полный, чем jstat. Он позволяет получать различную информацию о статистике производительности, Java Flight Recorder (JFR), использовании памяти, сборке мусора, наложении потоков и времени выполнения JVM целевого процесса Java.

Комплексные графические диагностические инструменты

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

  1. Они не могут получить аналитические данные на уровне метода, такие как взаимосвязь вызовов между различными методами, а также частоту и продолжительность вызова метода. Они очень важны для выявления узких мест в производительности вашего приложения.
  2. Вы должны войти в систему на главном компьютере целевого Java-приложения, чтобы использовать их, что не очень удобно.
  3. Аналитические данные генерируются на терминале, а результаты не отображаются интуитивно.

Ниже приведены несколько комплексных графических инструментов диагностики производительности:

JVisualvm

JVisualvm - это встроенный инструмент визуальной диагностики производительности, предоставляемый JDK. Он получает аналитические данные целевой JVM, включая использование ЦП, использование памяти, потоки, кучи и стеки, с помощью различных методов, таких как JMX, jstatd и Attach API. Кроме того, он может интуитивно отображать количество и размер каждого объекта в кучах Java, количество вызовов метода Java и продолжительность выполнения метода Java.

JProfiler

JProfiler - это инструмент диагностики производительности Java-приложений, разработанный компанией ej-technologies. Основное внимание в нем уделяется четырем важным темам:

  1. Вызов методов - анализ вызовов методов помогает вам понять, что делает ваше приложение, и найти способы улучшить его производительность.
  2. Распределения - посредством анализа объектов в куче, ссылочных цепочек и сборки мусора эта функция позволяет исправить утечки памяти и оптимизировать использование памяти.
  3. Поток и блокировка - JProfiler предоставляет несколько аналитических представлений о потоках и блокировках, чтобы помочь вам обнаружить проблемы многопоточности.
  4. Подсистемы высокого уровня. Многие проблемы с производительностью возникают на более высоком семантическом уровне. Например, с помощью вызовов Java Database Connectivity (JDBC) вы, вероятно, захотите выяснить, какой оператор SQL является самым медленным. JProfiler поддерживает комплексный анализ этих подсистем.

Диагностика производительности распределенных приложений

Если вам нужно только диагностировать узкие места в производительности автономных приложений Java, описанных выше диагностических инструментов будет достаточно, чтобы удовлетворить ваши потребности. Однако, когда автономные современные системы постепенно превращаются в распределенные системы и микросервисы, перечисленные выше инструменты не могут соответствовать требованиям. Нам необходимо использовать функцию сквозного слежения в распределенных системах слежения, таких как Jaeger, ARMS и SkyWalking. На рынке доступно множество распределенных систем отслеживания, но механизмы их реализации схожи. Они записывают информацию трассировки с помощью отслеживания кода, передают записанные данные в системы централизованной обработки через SDK или агентов и предоставляют интерфейсы запросов для отображения и анализа результатов. Дополнительные сведения о принципах работы распределенных систем трассировки см. В статье Реализация Jaeger в OpenTracing.

Введение в JProfiler

Основные компоненты

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

Агент JProfiler

Агент JProfiler реализован в виде собственной библиотеки. Вы можете загрузить его при запуске JVM, используя параметр -agentpath:<path to native library>, или когда приложение работает, используя Механизм присоединения JVM. После загрузки агента JProfiler он настраивает среду интерфейса инструмента JVM (JVMTI) для отслеживания всех видов событий, генерируемых JVM, таких как создание потока и загрузка класса. Например, когда он обнаруживает событие загрузки класса, агент JProfiler вставляет свой собственный байт-код в эти классы для выполнения своих измерений.

JProfiler UI

Пользовательский интерфейс JProfiler запускается отдельно и подключается к агенту профилирования через сокет. Это означает, что на самом деле не имеет значения, работает ли профилируемая JVM на локальном или удаленном компьютере - механизм связи между агентом профилирования и пользовательским интерфейсом JProfiler всегда одинаков.

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

Инструменты командной строки

JProfiler предоставляет ряд инструментов командной строки для реализации различных функций.

  • jpcontroller - используется для управления сбором данных агентом. Он отправляет инструкции агенту через MBean JProfiler, зарегистрированный агентом.
  • jpenable - используется для загрузки агента в работающую JVM.
  • jpdump - используется для захвата снимков кучи работающей JVM.
  • jpexport & jpcompare - используется для извлечения данных и создания отчетов HTML из ранее сохраненных снимков.

Установка

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

  1. Установите JProfiler UI локально.
  2. Установите агент JProfiler на удаленный хост-компьютер и загрузите его в целевую JVM.
  3. Подключите JProfiler UI к агенту.

Дополнительные сведения об этапах установки см. В разделах Установка JProfiler и Профилирование JVM.

Лучшие практики

В этом разделе показано, как использовать JProfiler для диагностики производительности Alibaba Cloud LOG Java Producer (Производитель), библиотеки классов LogHub. Если вы столкнетесь с проблемами производительности вашего приложения или при использовании Producer, вы можете предпринять аналогичные меры, чтобы выяснить основную причину. Если вы не знаете Producer, мы рекомендуем вам сначала прочитать эту статью: Alibaba Cloud LOG Java Producer - мощный инструмент для переноса журналов в облако.

Пример кода, использованного в этом разделе, см. В SamplePerformance.java.

Настройки JProfiler

Режим сбора данных

JProfiler предоставляет два метода сбора данных: отбор проб и инструментарий.

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

В этом примере нам нужно получить статистическую информацию на уровне метода, поэтому мы выбираем инструментальный метод. Фильтр настроен так, чтобы агент записывал данные ЦП только двух классов, com.aliyun.openservices.aliyun.log.producer и com.aliyun.openservices.log.Client, в пакете java.

Режимы запуска приложения

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

  • Дождитесь подключения из графического интерфейса JProfiler - приложение запускается только тогда, когда графический интерфейс JProfiler устанавливает соединение с агентом профилирования и настройки профилирования завершены. С помощью этой опции вы можете профилировать фазу запуска вашего приложения. Команда, которую вы можете использовать для включения этой опции: -agentpath:<path to native library>=port=8849.
  • Начните немедленно, подключитесь позже с графическим интерфейсом JProfiler - графический интерфейс JProfiler устанавливает соединение с агентом профилирования, когда это необходимо, и передает настройки профилирования. Этот вариант является гибким, но он не может профилировать этап запуска вашего приложения. Команда, которую вы можете использовать для включения этой опции: -agentpath:<path to native library>=port=8849,nowait.
  • Профиль в автономном режиме, JProfiler не может подключиться - вам необходимо настроить триггеры, которые записывают данные и сохраняют моментальные снимки, которые впоследствии можно будет открыть с помощью графического интерфейса JProfiler. Команда, которую можно использовать для включения этой опции: -agentpath:<path to native library>=offline,id=xxx,config=/config.xml.

В среде тестирования нам необходимо определить производительность приложения на этапе запуска. Поэтому мы используем здесь вариант WAIT по умолчанию.

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

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

Обзор

На странице обзора мы можем четко просматривать графики (телеметрии) различных метрик, таких как память, действия сборщика мусора, классы, потоки и загрузка ЦП.

На основании этой телеметрии мы можем сделать следующие предположения:

  1. В процессе работы приложения создается большое количество объектов. Эти объекты имеют очень короткий жизненный цикл, и большинство из них может быть быстро переработано сборщиком мусора. Они не приведут к постоянному росту использования памяти.
  2. Как и ожидалось, количество загруженных классов быстро увеличивается во время периода запуска и стабилизируется после.
  3. Когда приложение запущено, многие потоки блокируются. Этому вопросу нужно уделить особое внимание.
  4. На этапе запуска приложения загрузка ЦП высока. Нам нужно выяснить, почему.

Просмотры процессора

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

Дерево вызовов

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

Для Producer метод SendProducerBatchTask.run() занимает большую часть времени. Если вы продолжите смотреть вниз, то обнаружите, что большую часть времени занимает выполнение метода Client.PutLogs().

Горячие точки

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

В этом представлении вы можете видеть, что следующие три метода: Client.PutLogs(), LogGroup.toByteArray() и SamplePerformance$1.run() требуют наибольшего времени для выполнения по отдельности.

График звонков

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

Здесь мы видим, что большая часть времени выполнения метода Client.PutLogs() тратится на сериализацию объекта. Следовательно, ключом к оптимизации производительности является обеспечение более эффективного метода сериализации.

Живая память

Представления оперативной памяти позволяют узнать подробные сведения о распределении и использовании памяти, чтобы помочь вам определить, есть ли утечка памяти.

Все объекты

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

Дерево вызовов распределения

В представлении «Дерево вызовов распределения» отображается объем памяти, выделенной каждому методу, в виде древовидной диаграммы. Как видите, SamplePerformance$1.run() и SendProducerBatchTask.run() - большие потребители памяти.

Распределение горячих точек

Если у вас много методов, вы можете быстро узнать, какому методу назначено больше всего объектов, в представлении «Горячие точки распределения».

История темы

В представлении «История потоков» интуитивно отображается состояние каждого потока в разные моменты времени.

Задачи, выполняемые разными потоками, имеют разные особенности состояния.

  • Поток Pool-1-thread-<M> периодически вызывает метод Producer.send () для асинхронной отправки данных. Они продолжали работать, пока запускалось приложение, но потом в основном блокировались. Причина этого явления в том, что производитель отправляет данные медленнее, чем скорость генерации данных, а размер кеша каждого экземпляра источника ограничен. После запуска приложения у Producer было достаточно памяти для кэширования данных, ожидающих отправки, поэтому pool-1-thread-<M> некоторое время оставался запущенным. Это объясняет, почему у приложения была высокая загрузка ЦП при запуске. По прошествии времени кэш-память полностью занята. pool-1-thread-<M> должен дождаться, пока производитель освободит достаточно места. Именно поэтому блокируется большое количество потоков.
  • aliyun-log-producer-0-mover обнаруживает и отправляет пакеты с истекшим сроком действия в IOThreadPool. Скорость накопления данных высокая, пакет производителя отправляется в IOThreadPool pool-1-thread-<M> сразу после того, как размер кэшированных данных достиг верхнего предела. Таким образом, поток движителя большую часть времени оставался бездействующим.
  • aliyun-log-producer-0-io-thread-<N> отправляет данные из IOThreadPool в указанное вами хранилище журналов, и это занимает большую часть времени в состоянии сетевого ввода-вывода.
  • aliyun-log-producer-0-success-batch-handlerhandles пакетов, которые были успешно отправлены в хранилище журналов. Обратный вызов прост и выполняется очень быстро. Таким образом, SuccessBatchHandler большую часть времени бездействовал.
  • aliyun-log-producer-0-failure-batch-handler обрабатывает пакеты, которые не удалось отправить в хранилище журналов. В нашем случае не удалось отправить никакие данные. Он все время бездействовал.

Согласно нашему анализу, статусы этих тем находятся в пределах наших ожиданий.

Обнаружены горячие точки над головой

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

Резюме

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

использованная литература

Первоисточник

Https://www.alibabacloud.com/blog/jprofiler-best-practices-powerful-performance-diagnostic-tool_594958?spm=a2c41.13091385.0.0