Gymterview
middle

Что такое Micrometer и как его использовать в Spring Boot?

Micrometer — библиотека-фасад для сбора метрик в JVM-приложениях. По аналогии с SLF4J для логирования, Micrometer предоставляет единый API для работы с метриками, а конкретная реализация (backend) подключается отдельно.

Аналогия из жизни: Micrometer — это как универсальная розетка-переходник. Вы подключаете прибор (приложение) через один стандартный разъём, а на выходе можете подключить любую сеть — Prometheus, Datadog, CloudWatch.

Поддерживаемые бэкенды

Prometheus, Datadog, New Relic, CloudWatch, InfluxDB, Graphite, StatsD, Dynatrace, Elastic, Wavefront, OpenTelemetry.

Подключение к Spring Boot

Пример
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- Для экспорта в Prometheus -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Пример
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health, info, metrics, prometheus
  metrics:
    tags:
      application: ${spring.application.name}
    distribution:
      percentiles-histogram:
        http.server.requests: true
      sla:
        http.server.requests: 100ms, 500ms, 1s

MeterRegistry — центральный компонент

MeterRegistry — интерфейс, через который регистрируются все метрики. Spring Boot автоматически создаёт и настраивает нужную реализацию.

Пример OrderMetrics с Counter, Timer, Gauge
@Component
public class OrderMetrics {
    private final Counter createdOrders;
    private final Timer orderProcessingTimer;
    private final AtomicInteger pendingOrders = new AtomicInteger(0);

    public OrderMetrics(MeterRegistry registry) {
        this.createdOrders = Counter.builder("orders.created.total")
            .description("Total number of created orders")
            .register(registry);

        this.orderProcessingTimer = Timer.builder("orders.processing.duration")
            .description("Order processing duration")
            .publishPercentiles(0.5, 0.95, 0.99)
            .publishPercentileHistogram()
            .register(registry);

        Gauge.builder("orders.pending", pendingOrders, AtomicInteger::get)
            .description("Number of pending orders")
            .register(registry);
    }

    public void onOrderCreated() {
        createdOrders.increment();
        pendingOrders.incrementAndGet();
    }

    public void onOrderProcessed() {
        pendingOrders.decrementAndGet();
    }

    public Timer getProcessingTimer() {
        return orderProcessingTimer;
    }
}

Аннотация @Timed

Пример
@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @Timed(value = "orders.get.time",
           description = "Time to get orders",
           percentiles = {0.5, 0.95, 0.99})
    @GetMapping
    public List<Order> getOrders() {
        return orderService.findAll();
    }
}

Для работы @Timed необходимо зарегистрировать TimedAspect:

Пример
@Configuration
public class MetricsConfig {
    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }
}

Тэги (Dimensions) — ключевая концепция

Тэги позволяют разбивать метрики по измерениям (dimensions). Одна метрика с разными тэгами даёт множество временных рядов.

Пример
Counter.builder("http.requests")
    .tag("method", "GET")
    .tag("uri", "/api/orders")
    .tag("status", "200")
    .register(registry);
Пример
// Общие тэги для всех метрик приложения
@Bean
public MeterRegistryCustomizer<MeterRegistry> commonTags() {
    return registry -> registry.config()
        .commonTags("service", "order-service")
        .commonTags("env", "production")
        .commonTags("region", "eu-west-1");
}

Автоматические метрики Spring Boot

Группа Метрики Описание
JVM jvm.memory.used, jvm.memory.max, jvm.gc.pause Память, GC, потоки
HTTP http.server.requests Все HTTP-запросы (метод, URI, статус, время)
HikariCP hikaricp.connections.active, hikaricp.connections.idle Пул соединений к БД
Kafka kafka.consumer.records.consumed.total Метрики Kafka consumer/producer
Cache cache.gets, cache.puts, cache.evictions Метрики кэша
Logback logback.events Количество лог-событий по уровням
System system.cpu.usage, process.cpu.usage CPU, открытые файлы
Кастомный MeterBinder
@Component
public class BusinessMetricsBinder implements MeterBinder {
    private final OrderRepository orderRepository;

    public BusinessMetricsBinder(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    @Override
    public void bindTo(MeterRegistry registry) {
        Gauge.builder("orders.total.in.db", orderRepository, OrderRepository::count)
            .description("Total orders in database")
            .register(registry);
    }
}
Пример Prometheus-выхода (/actuator/prometheus)
# HELP http_server_requests_seconds Duration of HTTP server request handling
# TYPE http_server_requests_seconds histogram
http_server_requests_seconds_bucket{method="GET",status="200",uri="/api/orders",le="0.1"} 450
http_server_requests_seconds_bucket{method="GET",status="200",uri="/api/orders",le="0.5"} 498
http_server_requests_seconds_bucket{method="GET",status="200",uri="/api/orders",le="+Inf"} 500
http_server_requests_seconds_count{method="GET",status="200",uri="/api/orders"} 500
http_server_requests_seconds_sum{method="GET",status="200",uri="/api/orders"} 12.35

# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="G1 Eden Space"} 1.2345678E7

Важное

  • Micrometer — фасад, а не реализация. Без подключённого registry (например, micrometer-registry-prometheus) метрики собираются, но никуда не экспортируются.
  • Dimensional metrics (тэги) — основа модели Micrometer. В отличие от hierarchical (Graphite-стиль orders.eu.success), тэги позволяют гибко фильтровать и агрегировать.
  • Spring Boot 3.x использует Micrometer Observation API — единый механизм для метрик и трейсов одновременно.

Частые ошибки

  • Создание метрики при каждом вызове: Counter.builder(...).register(registry) внутри метода — метрика должна создаваться один раз (в конструкторе или @PostConstruct).
  • Динамические тэги с высокой кардинальностью: tag("userId", userId) создаёт отдельный time series для каждого пользователя.
  • Забыть подключить TimedAspect: без него аннотация @Timed на кастомных методах не работает (на контроллерах работает через WebMvcMetricsFilter).
  • Не настроить exposure endpoints: по умолчанию endpoint /actuator/prometheus не доступен; нужно явно добавить в management.endpoints.web.exposure.include.

Как используется в 2026

  • Micrometer Observation API — унифицированный API, одно «наблюдение» автоматически создаёт и метрику, и span трейса.
  • Micrometer Context Propagation — автоматическая передача контекста (traceId, MDC) между потоками, включая реактивные цепочки и виртуальные потоки.
  • Micrometer 2.x с нативной поддержкой OpenTelemetry Protocol (OTLP) для экспорта метрик напрямую в OTel Collector.
  • Большинство Spring Boot-стартеров (Data, Security, Kafka, RabbitMQ) поставляются с автоматическими Observation-хуками.

На собеседовании: ключевой тезис — Micrometer является фасадом (как SLF4J для логов). Покажите, что умеете выбирать тип метрики (Counter vs Gauge vs Timer), знаете про ограничение кардинальности тэгов и понимаете разницу между @Timed и Observation API в Spring Boot 3.x.