Перейти к основному содержимому

Знакомство с Алибабой Артас

· 8 мин. чтения

Задача: Медиана двух отсортированных массивов

Даны два отсортированных массива размерами n и m. Найдите медиану слияния этих двух массивов.
Временная сложность решения должна быть O(log(m + n)) ...

ANDROMEDA

1. Введение

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

В этом руководстве мы начнем с установки Arthas, прежде чем рассмотрим простой пример, чтобы продемонстрировать некоторые ключевые функции Arthas.

Наконец, поскольку Arthas написан на Java, он кроссплатформенный и будет успешно работать в Linux, macOS и Windows.

2. Загрузка и начало работы

Во-первых, давайте начнем с загрузки библиотеки Arthas либо напрямую по ссылке для скачивания , либо с помощью curl :

curl -O https://alibaba.github.io/arthas/arthas-boot.jar

Теперь давайте проверим его работу , запустив Arthas с опцией -h (help):

java -jar arthas-boot.jar -h

В случае успеха мы должны увидеть справочное руководство для всех отображаемых команд:

./9c5dde615a7af1ef040b6ef450c0a8ff.png

3. Тематическое исследование

В этом руководстве мы будем использовать очень простое приложение, основанное на довольно неэффективной реализации последовательности Фибоначчи с использованием рекурсии:

public class FibonacciGenerator {

public static void main(String[] args) {
System.out.println("Press a key to continue");
System.in.read();
for (int i = 0; i < 100; i++) {
long result = fibonacci(i);
System.out.println(format("fib(%d): %d", i, result));
}
}

public static long fibonacci(int n) {
if (n == 0 || n == 1) {
return 1L;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
}

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

В основном методе мы используем цикл for с относительно большими числами, поэтому наш компьютер будет занят более длительными вычислениями. Это, конечно, именно то, что мы хотим, чтобы продемонстрировать Артаса.

4. Запуск Артаса

А теперь попробуем Артаса! Первое, что нам нужно сделать, это запустить наше небольшое приложение Фибоначчи. Для этого мы можем использовать нашу любимую IDE или запустить ее прямо в терминале. Он попросит нажать клавишу, чтобы начать. Нажмем любую клавишу после того, как прикрепим процесс к Артасу.

Теперь давайте запустим исполняемый файл Arthas:

java -jar arthas-boot.jar

Артас предлагает меню, чтобы выбрать, к какому процессу мы хотим подключиться:

[INFO] arthas-boot version: 3.1.7
[INFO] Found existing java process, please choose one and hit RETURN.
* [1]: 25500 com.foreach.arthas.FibonacciGenerator
...

Давайте выберем тот, который называется com.foreach.arthas.FibonacciGenerator . Просто введите номер из списка, в данном примере «1», а затем нажмите Enter.

Теперь Артас подключится к этому процессу и начнет:

INFO] Try to attach process 25500
[INFO] Attach process 25500 success.
...

Как только мы запустим Arthas, у нас появится подсказка, в которой мы можем вводить различные команды.

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

После подключения Артаса к нашему процессу теперь мы можем нажать клавишу, и программа начнет печатать числа Фибоначчи.

5. Панель управления

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

./6e8f6c51eabf815bb2ea61f31530c3ff.png

Рассмотрим некоторые из них более подробно:

  1. Верхний раздел посвящен потокам, запущенным в данный момент.
  2. Одним из важных столбцов является потребление ЦП для каждого потока.
  3. В разделе 3 показано время ЦП на поток.
  4. Еще одна интересная панель предназначена для анализа памяти. Различные области памяти перечислены со своей статистикой. С правой стороны у нас есть информация о сборщике мусора .
  5. Наконец, в разделе 5 у нас есть информация о хост-платформе и JVM.

Мы можем выйти из приборной панели, нажав q .

Мы должны помнить, что Артас будет привязан к нашему процессу, даже если мы выйдем. Итак, чтобы правильно отвязать его от нашего процесса, нам нужно запустить команду остановки . **** ``

6. Анализ трассировки стека

В дашборде мы увидели, что наш основной процесс занимает почти 100% CPU. Этот процесс имеет идентификатор 1, который мы видим в самом первом столбце.

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

thread 1

Число, переданное в качестве аргумента, является идентификатором потока. Артас выводит трассировку стека, которая, что неудивительно, перегружена вызовами метода Фибоначчи .

Если трассировка стека длинная и утомительная для чтения, команда thread позволяет нам использовать конвейеры:

thread 1 | grep 'main('

Это напечатает только строку, соответствующую команде grep :

[arthas@25500]$ thread 1 | grep 'main('
at com.foreach.arthas.FibonacciGenerator.main(FibonacciGenerator.java:10)

7. Декомпилировать класс Java

Давайте представим ситуацию, когда мы анализируем Java-приложение, о котором мало или совсем ничего не знаем, и вдруг обнаруживаем, что стек усыпан повторяющимися вызовами типа:

[arthas@59816]$ thread 1
"main" Id=1 RUNNABLE
at app//com.foreach.arthas.FibonacciGenerator.fibonacci(FibonacciGenerator.java:18)
at app//com.foreach.arthas.FibonacciGenerator.fibonacci(FibonacciGenerator.java:18)
...

Поскольку мы запускаем Arthas, мы можем декомпилировать класс, чтобы увидеть его содержимое. Для этого мы можем использовать команду jad , передав полное имя класса в качестве аргумента:

jad com.foreach.arthas.FibonacciGenerator

ClassLoader:
+-jdk.internal.loader.ClassLoaders$AppClassLoader@799f7e29
+-jdk.internal.loader.ClassLoaders$PlatformClassLoader@60f1dd34

Location:
/home/amoreno/work/foreach/tutorials/libraries-3/target/
/*
* Decompiled with CFR.
*/
package com.foreach.arthas;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;

public class FibonacciGenerator {
public static void main(String[] arrstring) throws IOException {

Результатом является декомпилированный класс Java и некоторые полезные метаданные, такие как местоположение класса . Это действительно полезная и мощная функция.

8. Класс поиска и метод поиска

Команда search class удобна при поиске классов, загруженных в JVM. Мы можем использовать его, набрав sc и передав шаблон с подстановочными знаками или без них в качестве аргумента :

[arthas@70099]$ sc *Fibonacci*
com.foreach.arthas.FibonacciGenerator
Affect(row-cnt:1) cost in 5 ms.

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

  • -d для отображения сведений о классе
  • -f для отображения полей класса

Однако поля класса необходимо запрашивать вместе с деталями:

[arthas@70099]$ sc -df com.foreach.arthas.FibonacciGenerator
class-info com.foreach.arthas.FibonacciGenerator
...

Точно так же мы можем использовать команду sm (метод поиска) для поиска загруженных методов в классе. В этом случае для нашего класса com.foreach.arthas.FibonacciGenerator мы можем запустить:

[arthas@70099]$ sm com.foreach.arthas.FibonacciGenerator
com.foreach.arthas.FibonacciGenerator <init>()V
com.foreach.arthas.FibonacciGenerator main([Ljava/lang/String;)V
com.foreach.arthas.FibonacciGenerator fibonacci(I)J
Affect(row-cnt:3) cost in 4 ms.

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

sm -d com.foreach.arthas.FibonacciGenerator fibonacci
declaring-class com.foreach.arthas.FibonacciGenerator
method-name fibonacci
modifier public,static
annotation
parameters int
return long
exceptions
classLoaderHash 799f7e29

9. Мониторинг вызовов методов

Еще одна крутая вещь, которую мы можем делать с Артасом, — это мониторинг метода. Это может быть очень удобно при отладке проблем с производительностью в наших приложениях. Для этого мы можем использовать команду монитора .

Для команды монитора требуется флаг -c <секунды> и два аргумента — полное имя класса и имя метода.

Для нашего примера давайте теперь вызовем monitor :

monitor -c 10 com.foreach.arthas.FibonacciGenerator fibonacci

Как и ожидалось, Артас будет печатать метрики о методе Фибоначчи каждые 10 секунд:

Affect(class-cnt:1 , method-cnt:1) cost in 47 ms.
timestamp class method total success fail avg-rt(ms) fail-rate
-----------------------------------------------------------------------------------------------------------------------------
2020-03-07 11:43:26 com.foreach.arthas.FibonacciGenerator fibonacci 528957 528957 0 0.07 0.00%
...

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

10. Аргументы метода мониторинга

В случае, если нам нужно отладить параметры метода, мы можем использовать команду watch . Но синтаксис немного сложнее:

watch com.foreach.arthas.FibonacciGenerator fibonacci '{params[0], returnObj}' 'params[0]>10' -n 10

Рассмотрим подробно каждый из аргументов:

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

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

watch com.foreach.arthas.FibonacciGenerator fibonacci '{params[0], returnObj}' 'params[0]>10' -n 10
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 19 ms.
ts=2020-02-17 21:48:08; [cost=30.165211ms] result=@ArrayList[
@Integer[11],
@Long[144],
]
ts=2020-02-17 21:48:08; [cost=50.405506ms] result=@ArrayList[
@Integer[12],
@Long[233],
]
...

Здесь мы можем увидеть примеры вызовов с их процессорным временем и входными/возвратными значениями.

11. Профайлер

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

Запустим профилировщик, запустив profiler start . Это неблокирующая задача, то есть мы можем продолжать использовать Arthas, пока работает профайлер.

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

Давайте теперь остановим профилировщик с помощью остановки профилировщика. На этом этапе сохраняется изображение FlameGraph . Именно в этом случае у нас есть график с преобладающей нитью Фибоначчи :

./a8e7f6b1ac512168027964552b19aeb8.png

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

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

В этом уроке мы рассмотрели некоторые из самых мощных и полезных функций Arthas.

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

Как всегда, полный исходный код статьи доступен на GitHub .