← Назад к вопросам

Какие знаешь Metric у Spring Boot?

2.0 Middle🔥 161 комментариев
#Spring Boot и Spring Data

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Метрики в Spring Boot (Micrometer и Actuator)

Метрики — это количественные измерения поведения приложения (throughput, latency, error rates), необходимые для мониторинга, алертинга и отладки production систем. Spring Boot предоставляет встроенную поддержку через Micrometer и Actuator.

Основные компоненты

Micrometer — фасад для различных систем мониторинга (Prometheus, Grafana, Datadog, InfluxDB и др.). Spring Boot Actuator — встроенный модуль для сбора и предоставления метрик через HTTP endpoints.

Подключение

// 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>

Встроенные метрики Actuator

Spring Boot автоматически собирает следующие метрики:

JVM метрики:

  • jvm.memory.used — использование памяти (Heap/Non-Heap)
  • jvm.gc.memory.allocated — выделено памяти для GC
  • jvm.gc.max.data.size — максимум памяти для GC
  • jvm.gc.pause — время пауз garbage collection
  • jvm.threads.live — количество активных потоков
  • jvm.threads.peak — пик активных потоков
  • jvm.classes.loaded — загруженные классы

HTTP метрики (Servlet):

  • http.server.requests — счетчик HTTP запросов с labels (method, uri, status)
  • http.server.requests.max — максимальное время обработки
  • http.server.requests.active — активные запросы

Бизнес-метрики приложения:

  • process.uptime — время работы приложения
  • process.cpu.usage — использование CPU
  • system.cpu.usage — CPU системы в целом
  • system.memory.usage — использование системной памяти

Типы метрик Micrometer

1. Counter — монотонно растущий счетчик:

@Service
public class OrderService {
    private final MeterRegistry meterRegistry;
    private final AtomicInteger ordersCreated;
    
    public OrderService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.ordersCreated = meterRegistry.counter(
            "orders.created",
            "status", "total"
        ).count();
    }
    
    public void createOrder(Order order) {
        // Бизнес-логика
        meterRegistry.counter("orders.created", "status", "success").increment();
    }
}

2. Gauge — текущее значение (не монотонный):

@Service
public class QueueService {
    private final Queue<Task> taskQueue = new ConcurrentLinkedQueue<>();
    private final MeterRegistry meterRegistry;
    
    public QueueService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        // Регистрируем gauge — текущий размер очереди
        meterRegistry.gaugeCollectionSize(
            "queue.size",
            Tags.empty(),
            taskQueue
        );
    }
}

3. Timer — измерение времени выполнения операции:

@Service
public class PaymentService {
    private final MeterRegistry meterRegistry;
    
    public void processPayment(Payment payment) {
        // Способ 1: старый способ с Timer.Sample
        Timer.Sample sample = Timer.start(meterRegistry);
        try {
            // Обработка платежа
            callPaymentGateway(payment);
        } finally {
            sample.stop(Timer.builder("payment.processing.time")
                .description("Время обработки платежа")
                .publishPercentiles(0.5, 0.95, 0.99)
                .register(meterRegistry));
        }
        
        // Способ 2: через аннотацию
    }
    
    // Способ 2: декоратор через аннотацию @Timed
    @Timed(value = "payment.processing.time",
            description = "Время обработки платежа")
    public void processPaymentAnnotated(Payment payment) {
        // Обработка платежа
    }
}

4. Distribution Summary — распределение значений (без привязки ко времени):

@Service
public class FileUploadService {
    private final MeterRegistry meterRegistry;
    private final DistributionSummary uploadSize;
    
    public FileUploadService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.uploadSize = DistributionSummary.builder("file.upload.size")
            .description("Размер загруженного файла в байтах")
            .baseUnit("bytes")
            .scale(1024.0) // переводим в KB
            .register(meterRegistry);
    }
    
    public void uploadFile(byte[] content) {
        uploadSize.record(content.length);
    }
}

Собственные метрики через аннотацию

@Service
public class UserService {
    // @Timed выполняет метрику автоматически
    @Timed(value = "user.fetch", 
            description = "Время получения пользователя по ID")
    public User getUserById(Long id) {
        // Время выполнения метода автоматически записывается
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
    }
}

Tags (теги/labels) для группировки

Метрики могут иметь теги для более детального анализа:

@Service
public class ApiService {
    private final MeterRegistry meterRegistry;
    
    public void handleRequest(String endpoint, int statusCode) {
        meterRegistry.counter(
            "api.requests",
            "endpoint", endpoint,        // group by endpoint
            "status", String.valueOf(statusCode) // group by status
        ).increment();
    }
}

// Результат в Prometheus:
// api_requests{endpoint="/users",status="200"} 150
// api_requests{endpoint="/users",status="404"} 5
// api_requests{endpoint="/orders",status="200"} 320

Endpoints Actuator

# Все доступные endpoints
GET /actuator

# Метрики (JSON)
GET /actuator/metrics

# Конкретная метрика
GET /actuator/metrics/jvm.memory.used

# Для Prometheus (текстовый формат)
GET /actuator/prometheus

# Здоровье приложения
GET /actuator/health

# Информация о приложении
GET /actuator/info

# Логирование
GET /actuator/loggers
POST /actuator/loggers/com.example

Конфигурация в application.yml

management:
  endpoints:
    web:
      exposure:
        include: prometheus,health,info,metrics
  metrics:
    distribution:
      percentiles-histogram:
        http.server.requests: true
      slo:
        http.server.requests: 100ms,500ms,1s
  endpoint:
    health:
      show-details: when-authorized

Практический пример с Dashboard

@Service
public class AnalyticsService {
    private final MeterRegistry meterRegistry;
    
    public AnalyticsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // Active users gauge
        meterRegistry.gauge("users.active", 
            () -> userRepository.countActiveUsers());
        
        // Revenue counter
        meterRegistry.counter("revenue.total", 
            "currency", "USD");
        
        // API latency timer
        Timer.builder("api.latency")
            .publishPercentiles(0.5, 0.95, 0.99)
            .minimumExpectedValue(Duration.ofMillis(1))
            .maximumExpectedValue(Duration.ofSeconds(10))
            .register(meterRegistry);
    }
    
    public void recordPayment(BigDecimal amount) {
        meterRegistry.counter("revenue.total", 
            "currency", "USD").increment(amount.doubleValue());
    }
}

Интеграция с Prometheus и Grafana

  1. Prometheus скрейпит /actuator/prometheus каждые 15 секунд
  2. Grafana создает дашборды на основе метрик
  3. Alerting правила срабатывают при превышении пороговых значений

Метрики в Spring Boot — это основа наблюдаемости (observability) современных приложений, позволяющая быстро обнаруживать проблемы и оптимизировать систему.