Используйте удаленный мониторинг Java-программ на уровне метода Metrics.

Java

В этой статье объясняется фоновая разработка Spring Web.

В предыдущей статье объяснялось, как использоватьjvisualvmМониторинг Java-программ.jvisualvmХотя он довольно мощный, он все же не отвечает нашим потребностям в практических приложениях. Теперь мы хотим отслеживать всеControllerКоличество обращений, частота и время отклика предоставленного интерфейса.ServiceВремя выполнения метода слоя, время выполнения, частота и т. д. Чтобы подготовиться к оптимизации производительности системы позже. В настоящее времяjvisualvmОн больше не может удовлетворить наши потребности.

1 Мониторинг Java-программ на уровне методов

Это мое решение для Java-программы мониторинга на уровне методов:

  1. Платные, такие как YourKit, JProfile и т.д. Я попробовал YourKit, он действительно мощный, но производительность не является нашим текущим узким местом, мы стараемся использовать бесплатные.
  2. Метрика - Весна. Metrics-Spring требует аннотаций для каждого метода. Мы используем микросервисную архитектуру с более чем 20 сервисами, и ожидается, что каждый проект будет иметь в среднем около 100 методов для мониторинга. Я думаю, что это нормально, если он используется в первую очередь.
  3. Метрики + Spring АОП. Как видно из Metrics-Spring, статистическая информация Metrics в основном соответствует нашим потребностям. Наши требования к проекту - статистикаControllerслой иServiceслойный метод. Затем мы можем завершить наши потребности через аспекты в Spring.

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

Ниже приводится объяснение + часть кода, и в этом объяснении есть статьи по оптимизации.

2. Функции метрик

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

  1. Введение в метрики. В этой статье очень подробно представлены основные функции метрик.
  2. Официальная документация Metrics-Spring. В этой статье рассказывается об интеграции Metrics и Spring, но документация кажется неполной.

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

3 Загрузите классы, связанные с метриками, в контейнер Spring.

Чтобы использовать Метрику, вам сначала нужноMetricRegistry.

Нам нужно предоставить отчеты Http, поэтому нам нужноMetricsServletЗарегистрируйтесь в Spring, чтобы результаты мониторинга можно было получать через Http-интерфейс. В следующем коде мы определяем интерфейс мониторинга как:/monitor/metrics.

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.servlets.MetricsServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MonitorConfig {

    @Bean
    public MetricRegistry metricRegistry() {
        return new MetricRegistry();
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean(MetricRegistry metricRegistry) {
        return new ServletRegistrationBean(new MetricsServlet(metricRegistry), "/monitor/metrics");
    }

}

4 предоставляет контролируемые отчеты терминала

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

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import lombok.extern.java.Log;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.util.concurrent.TimeUnit;

@Configuration
@Log
@ConditionalOnProperty(prefix = "monitor.report", name = "console", havingValue = "true")
@Import(MonitorConfig.class)
public class MonitorReportConfig {


    @Bean
    public ConsoleReporter consoleReporter(MetricRegistry metrics) {
        ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(10, TimeUnit.SECONDS);
        return reporter;
    }

}

Это можно сделать в проектеapplication.propertiesВ файле откройте отчет терминала через следующую конфигурацию и выводите его каждые 10 секунд:

monitor.report.console = true

5 Подготовьте таймер для контролируемого метода

Информации, которую можно посчитать в Метрике, очень много, и Timer уже собрал нужную нам информацию.

Почему я должен сначала подготовить таймер для отслеживаемого метода, а не создавать его при выполнении метода? Есть две причины.

  1. Нам важно не только то, что метод вызывается, но и то, что он никогда не вызывается, если он создается при выполнении метода, то мы не знаем, не отслеживается ли метод или метод не вызывается.
  2. Позже мы планируем напрямую фасетировать аннотации @RestController, @Controller и @Service. Эта сила аспекта на уровне класса будет включать в себя методы, которые нам не нужны, такие как toString и другие методы, поэтому подготовьте методы, которые вам нужны, и когда вы их вызовете, вы обнаружите, что вам не нужны методы, и пусть они идут.

Мы используемMethodMonitorCenterкласс для сбора методов, которые мы хотим отслеживать. путем реализацииApplicationContextAwareИнтерфейс после загрузки контейнера Spring будет возвращенsetApplicationContextметод, мы проходимgetBeansWithAnnotationМетод находит класс, содержащий указанную аннотацию. Затем отфильтруйте его и получите методы, которые мы хотим отслеживать. В конце мы проходимmetricRegistry.timer(method.toString());метод подготавливает таймер для интересующего нас метода.

@Component
@Getter
@Log
public class MethodMonitorCenter implements ApplicationContextAware {

    public static final String PACKAGE_NAME = "com.sinafenqi";  // 这里换成自己的包名

    @Autowired
    private MetricRegistry metricRegistry;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> monitorBeans = new HashMap<>();
        monitorBeans.putAll(applicationContext.getBeansWithAnnotation(Controller.class));
        monitorBeans.putAll(applicationContext.getBeansWithAnnotation(Service.class));
        monitorBeans.putAll(applicationContext.getBeansWithAnnotation(RestController.class));

        log.info("monitor begin scan methods");
        monitorBeans.values().stream()
                .map(obj -> obj.getClass().getName())
                .map(this::trimString)
                .map(clzName -> {
                    try {
                        return Class.forName(clzName);
                    } catch (Exception e) {
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .filter(aClass -> aClass.getName().startsWith(PACKAGE_NAME))
                .forEach(this::getClzMethods);
    }

    private void getClzMethods(Class<?> clz) {
        Stream.of(clz.getDeclaredMethods())
                .filter(method -> method.getName().indexOf('$') < 0)
                .forEach(method -> {
                    log.info("add method timer, method name :" + method.toGenericString());
                    metricRegistry.timer(method.toString());
                });
    }

    private String trimString(String clzName) {
        if (clzName.indexOf('$') < 0) return clzName;
        return clzName.substring(0, clzName.indexOf('$'));
    }

}

6 Методы мониторинга по аспектам

Затем мы можем отслеживать интересующие нас методы в аспекте. Используйте фасеты с закруглением здесьRestController,ControllerServiceТри аннотации делают аспект. Это позволяет вам добавить некоторый код мониторинга до и после метода. При входе в функцию вокруг мы сначала идем в MetricRegistry, чтобы узнать, есть ли соответствующий таймер.Если нет описания, которое не является интересующим нас методом, то мы можем выполнить его напрямую.Если оно есть, то я буду мониторить Это. Подробности смотрите в коде:

@Component
@Aspect
@Log
public class MetricsMonitorAOP {

    @Autowired
    private MetricRegistry metricRegistry;

    @Pointcut("@within(org.springframework.stereotype.Controller)" +
            "||@within(org.springframework.stereotype.Service)" +
            "||@within(org.springframework.web.bind.annotation.RestController)")
    public void monitor() {

    }

    @Around("monitor()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String target = joinPoint.getSignature().toLongString();
        Object[] args = joinPoint.getArgs();
        if (!metricRegistry.getNames().contains(target)) {
            return joinPoint.proceed(args);
        }
        Timer timer = metricRegistry.timer(target);
        Timer.Context context = timer.time();
        try {
            return joinPoint.proceed(args);
        } finally {
            context.stop();
        }
    }
}

7 эффектов

посетить после/monitor/metricsинтерфейс, вы можете получить результаты мониторинга в формате данных Json. Не забудьте поставитьMethodMonitorCenterв классеPACKAGE_NAMEЗамените константу на свою.

Теперь мы в основном реализовали методы, которые мы определили для мониторинга всех уровней контроллеров и сервисов, но в коде еще много места для оптимизации. Я нашел эти коды в репозитории Git и больше не пробовал.Если у вас есть какие-либо вопросы, пожалуйста, оставьте сообщение. Пожалуйста, поймите. В настоящее время я оптимизировал код во многих местах, содержание оптимизации будет объяснено в следующей статье, а исходный код будет прикреплен.

Наконец, приглашаю обратить внимание на мой личный публичный номер. Задавайте вопросы, общайтесь, что угодно.

假不正经程序员