Мониторинг приложений Java: библиотека Micrometer
Современные Java-приложения требуют постоянного наблюдения за производительностью, потреблением памяти, временем отклика и другими критическими параметрами. Micrometer — это де-факто стандартная библиотека для сбора метрик в экосистеме Java, которая предоставляет универсальный API и поддерживает экспорт данных в популярные системы мониторинга, такие как Prometheus, Graphite и Datadog.
Что такое Micrometer и зачем он нужен?
Micrometer — это фасад для сбора метрик, аналогичный тому, как SLF4J является фасадом для логирования. Он абстрагирует код приложения от конкретной системы мониторинга, позволяя переключаться между бэкендами без изменения бизнес-логики.
Основные возможности библиотеки:
- Счётчики (Counter) — для подсчёта событий (например, количество запросов).
- Таймеры (Timer) — для измерения времени выполнения операций.
- Датчики (Gauge) — для отслеживания текущих значений (например, размер пула потоков).
- Распределения (DistributionSummary) — для анализа распределения значений (например, размер тела запроса).
- Теги (Tags) — для добавления размерностей к метрикам (например,
endpoint,status).
Установка и настройка
Для использования Micrometer в проекте Maven добавьте следующую зависимость в pom.xml:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>1.12.0</version>
</dependency>
Если вы используете Spring Boot, достаточно подключить стартер micrometer-registry-prometheus:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.12.0</version>
</dependency>
После этого Spring Boot автоматически сконфигурирует MeterRegistry и откроет эндпоинт /actuator/prometheus для сбора метрик.
Примеры использования
1. Создание счётчика запросов
Простой пример подсчёта количества вызовов метода:
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
public class RequestCounter {
private final Counter requestCounter;
public RequestCounter(MeterRegistry registry) {
this.requestCounter = Counter.builder("api.requests")
.tag("endpoint", "/users")
.description("Total number of requests to /users")
.register(registry);
}
public void handleRequest() {
requestCounter.increment();
// бизнес-логика
}
}
2. Измерение времени выполнения с помощью таймера
Используйте Timer.Sample для измерения времени выполнения блока кода:
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.MeterRegistry;
public class RequestTimer {
private final Timer requestTimer;
public RequestTimer(MeterRegistry registry) {
this.requestTimer = Timer.builder("api.response.time")
.tag("endpoint", "/data")
.publishPercentiles(0.95, 0.99)
.register(registry);
}
public String processRequest() {
Timer.Sample sample = Timer.start(registry);
try {
// эмуляция задержки
Thread.sleep(100);
return "OK";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "ERROR";
} finally {
sample.stop(requestTimer);
}
}
}
3. Отслеживание размера пула потоков через Gauge
Gauge показывает текущее значение, которое может меняться со временем:
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolMonitor {
private final AtomicInteger activeThreads = new AtomicInteger(0);
public ThreadPoolMonitor(MeterRegistry registry) {
Gauge.builder("threadpool.active", activeThreads, AtomicInteger::get)
.tag("pool", "worker")
.description("Number of active threads")
.register(registry);
}
public void executeTask(Runnable task) {
activeThreads.incrementAndGet();
try {
task.run();
} finally {
activeThreads.decrementAndGet();
}
}
}
Интеграция с Prometheus и Grafana
После настройки Micrometer метрики будут доступны по эндпоинту /actuator/prometheus. Чтобы собрать их в Prometheus, добавьте в prometheus.yml следующую конфигурацию: