Статьи

BTrace: скрытая жемчужина в наборе инструментов разработчика Java

Этот пост о BTrace, который я рассматриваю как скрытое сокровище для разработчика Java. BTrace — безопасный, динамический инструмент трассировки для платформы Java. BTrace можно использовать для динамического отслеживания работающей программы Java (аналогично DTrace для приложений и ОС OpenSolaris).

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

Что очень круто, BTrace сам использует язык Java для определения точек трассировки инъекций. Подход выглядит очень знакомым, если вы когда-либо занимались аспектно-ориентированным программированием (AOP).

Итак, давайте начнем с проблемы: у нас есть приложение, которое использует одну из баз данных NoSQL (например, пусть это будет MongoDB) и внезапно начинает испытывать значительное снижение производительности. Разработчики подозревают, что приложение запускает слишком много запросов или обновлений, но не могут сказать это с уверенностью. Здесь BTrace может помочь.

Прежде всего, давайте запустим JVisualVM и установим плагин BTrace:

JVisualVM должен быть перезапущен для появления плагина. Теперь, когда наше приложение запущено, давайте щёлкнем по нему правой кнопкой мыши в дереве приложений JVisualVM :

Должен появиться следующий очень интуитивный редактор BTrace (с простой панелью инструментов):

Это место, где инструменты трассировки могут быть определены и динамически внедрены в работающее приложение. BTrace имеет очень богатую модель для определения того, что именно следует отслеживать: методы, конструкторы, возвраты метода, ошибки,…. Также он поддерживает агрегацию из коробки, так что довольно легко собрать кучу метрик во время работы приложения. Для нашей проблемы мы хотели бы увидеть, какие методы, связанные с MongoDB, выполняются.

Поскольку мое приложение использует Spring Data MongoDB , меня интересует, какие методы любой реализации интерфейса org.springframework.data.mongodb.core.MongoOperations вызываются приложением и сколько времени занимает каждый вызов. Итак, я определил очень простой скрипт BTrace :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import com.sun.btrace.*;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
 
@BTrace
public class TracingScript {
    @TLS private static String method;
 
    @OnMethod(
        clazz = '+org.springframework.data.mongodb.core.MongoOperations',
        method = '/.*/'
    )
    public static void onMongo(
            @ProbeClassName String className,
            @ProbeMethodName String probeMethod,
            AnyType[] args ) {
        method = strcat( strcat( className, '::' ), probeMethod );
    }
     
    @OnMethod(
        clazz = '+org.springframework.data.mongodb.core.MongoOperations',
        method = '/.*/',
        location = @Location( Kind.RETURN )
    )
    public static void onMongoReturn( @Duration long duration ) {
         println( strcat( strcat( strcat( strcat( 'Method ', method ),
            ' executed in ' ), str( duration / 1000 ) ), 'ms' ) );
    }
}

Позвольте мне кратко объяснить, что я здесь делаю. В основном, я хотел бы знать, когда вызывается любой метод любой реализации org.springframework.data.mongodb.core.MongoOperations ( это отмечает onMongo ) и продолжительность вызова ( onMongoReturn отмечает это, в свою очередь). Метод локальной переменной потока содержит полное имя метода (вместе с классом), в то время как благодаря полезной предопределенной аннотации BTrace параметр duration содержит время выполнения метода (в наносекундах). Хотя это чистая Java, BTrace позволяет использовать только небольшое подмножество классов Java. Это не проблема, так как класс com.sun.btrace.BTraceUtils предоставляет множество полезных методов (например, strcat ) для заполнения пробелов. Запуск этого скрипта приводит к следующему выводу:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
** Compiling the BTrace script ...
*** Compiled
** Instrumenting 1 classes ...
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 25ms
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 3ms
Method org.springframework.data.mongodb.core.MongoTemplate::getDb executed in 22ms
Method org.springframework.data.mongodb.core.MongoTemplate::prepareCollection executed in 2ms
Method org.springframework.data.mongodb.core.MongoTemplate::prepareCollection executed in 19ms
Method org.springframework.data.mongodb.core.MongoTemplate::access$100 executed in 2ms
Method org.springframework.data.mongodb.core.MongoTemplate::access$100 executed in 1ms
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 3ms
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 2ms
Method org.springframework.data.mongodb.core.MongoTemplate::getDb executed in 2ms
Method org.springframework.data.mongodb.core.MongoTemplate::prepareCollection executed in 1ms
Method org.springframework.data.mongodb.core.MongoTemplate::prepareCollection executed in 6ms
Method org.springframework.data.mongodb.core.MongoTemplate::access$100 executed in 1ms
Method org.springframework.data.mongodb.core.MongoTemplate::access$100 executed in 0ms
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 2ms
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 1ms
Method org.springframework.data.mongodb.core.MongoTemplate::getDb executed in 2ms
Method org.springframework.data.mongodb.core.MongoTemplate::prepareCollection executed in 1ms
Method org.springframework.data.mongodb.core.MongoTemplate::prepareCollection executed in 6ms
Method org.springframework.data.mongodb.core.MongoTemplate::access$100 executed in 1ms
Method org.springframework.data.mongodb.core.MongoTemplate::access$100 executed in 0ms
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 2ms
Method org.springframework.data.mongodb.core.MongoTemplate::maybeEmitEvent executed in 1ms
...

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

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

Ссылка: BTrace: скрытая жемчужина в наборе инструментов для разработчиков Java от нашего партнера по JCG Андрея Редько в блоге Андрея Редько {devmind} .