УРОК 21 / 30 0%

Spring Boot Actuator + Micrometer + Prometheus

🎯

Цель урока

Сделать полноценный CRUD для задач с правильными HTTP-статусами (201/204/404), обработкой ошибок, и подготовить Task к подключению JPA.

🧠

Теория · для собеса

1 Зачем Actuator

Spring Boot Actuator добавляет production-ready endpoints:

  • /actuator/health — приложение живо?
  • /actuator/info — метаданные
  • /actuator/metrics — JVM, HTTP, DB, cache метрики
  • /actuator/prometheus — в формате Prometheus
  • /actuator/loggers — управление уровнями логирования
  • /actuator/env — переменные окружения
  • /actuator/threaddump — дамп потоков (debug)
2 Micrometer

Micrometer — абстракция для метрик. Backend-agnostic: можно менять Prometheus → DataDog → CloudWatch без переписывания кода.

3 Prometheus + Grafana

Spring Boot (micrometer-registry-prometheus)
   ↓ /actuator/prometheus
   ↓
Prometheus (scrapes every 15s)
   ↓
Grafana (dashboards)

---

💻

Практика: улучшаем CRUD

  1. 1
    Зависимости
    
    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-actuator")
        implementation("io.micrometer:micrometer-registry-prometheus")
    }
    
  2. 2
    application.yml
    
    management:
      endpoints:
        web:
          exposure:
            include: health,info,metrics,prometheus,loggers
          base-path: /actuator
      endpoint:
        health:
          show-details: when_authorized  # подробности только для админа
          probes:
            enabled: true  # для K8s liveness/readiness
      metrics:
        tags:
          application: ${spring.application.name}
          profile: ${spring.profiles.active:default}
      prometheus:
        metrics:
          export:
            enabled: true
    
    # SecurityConfig — actuator открыт для scrape'а Prometheus
    # В продакшене лучше отдельный порт (см. ниже)
    
  3. 3
    Endpoints
    
    # Liveness/readiness для K8s
    GET /actuator/health/liveness    # "status": "UP" — приложение живо
    GET /actuator/health/readiness   # "status": "UP" — готово принимать трафик
    
    # Метрики
    GET /actuator/metrics            # список метрик
    GET /actuator/metrics/jvm.memory.used  # конкретная метрика
    GET /actuator/prometheus         # в формате Prometheus
    
    # Логи
    GET /actuator/loggers            # все логгеры и их уровни
    POST /actuator/loggers/com.taskflow  # изменить уровень (admin only)
    
    # Info
    GET /actuator/info
    
  4. 4
    Пример вывода /actuator/prometheus
    
    # HELP jvm_memory_used_bytes The amount of used memory
    # TYPE jvm_memory_used_bytes gauge
    jvm_memory_used_bytes{application="taskflow",area="heap",id="G1 Eden Space",} 1.2345678E7
    
    # HELP http_server_requests_seconds
    # TYPE http_server_requests_seconds summary
    http_server_requests_seconds_count{method="GET",outcome="200",status="200",uri="/api/tasks",} 42.0
    http_server_requests_seconds_sum{method="GET",outcome="200",status="200",uri="/api/tasks",} 1.234
    
    # HELP hikaricp_connections_active
    # TYPE hikaricp_connections_active gauge
    hikaricp_connections_active{pool="HikariPool-1",} 3.0
    
  5. 5
    Custom метрики
    
    package com.taskflow.metrics;
    
    import io.micrometer.core.instrument.Counter;
    import io.micrometer.core.instrument.MeterRegistry;
    import io.micrometer.core.instrument.Timer;
    import org.springframework.stereotype.Component;
    
    @Component
    public class TaskMetrics {
        private final Counter tasksCreated;
        private final Counter tasksDeleted;
        private final Timer taskCreationTimer;
    
        public TaskMetrics(MeterRegistry registry) {
            this.tasksCreated = Counter.builder("taskflow.tasks.created")
                .description("Total number of tasks created")
                .register(registry);
    
            this.tasksDeleted = Counter.builder("taskflow.tasks.deleted")
                .description("Total number of tasks deleted")
                .register(registry);
    
            this.taskCreationTimer = Timer.builder("taskflow.task.creation.time")
                .description("Time to create a task")
                .publishPercentiles(0.5, 0.95, 0.99)
                .register(registry);
        }
    
        public void incrementCreated() { tasksCreated.increment(); }
        public void incrementDeleted() { tasksDeleted.increment(); }
        public Timer creationTimer() { return taskCreationTimer; }
    }
    
  6. 6
    Использование в TaskService
    
    @Service
    public class TaskService {
        // ...
        private final TaskMetrics metrics;
    
        public TaskService(..., TaskMetrics metrics) {
            // ...
            this.metrics = metrics;
        }
    
        public TaskResponse create(CreateTaskRequest req) {
            return metrics.creationTimer().record(() -> {
                User me = currentUser.get();
                Task task = mapper.toEntity(req);
                task.setOwner(me);
                Task saved = repo.save(task);
                metrics.incrementCreated();  // <-- Counter
                return mapper.toResponse(saved);
            });
        }
    
        public void delete(Long id) {
            // ...
            repo.delete(task);
            metrics.incrementDeleted();
        }
    }
    
  7. 7
    Отдельный порт для Actuator (безопасность)
    
    management:
      server:
        port: 9090          # отдельный порт, доступ только изнутри K8s
        address: 127.0.0.1  # слушает только localhost
    

    Тогда /actuator/prometheus доступен на localhost:9090, основной API — на :8080.

  8. 8
    Docker Compose с Prometheus + Grafana
    
    # docker-compose.monitoring.yml
    services:
      prometheus:
        image: prom/prometheus:latest
        volumes:
          - ./prometheus.yml:/etc/prometheus/prometheus.yml
        ports: ["9090:9090"]
    
      grafana:
        image: grafana/grafana:latest
        environment:
          GF_SECURITY_ADMIN_PASSWORD: admin
        ports: ["3000:3000"]
        depends_on: [prometheus]
    

    prometheus.yml:

    
    global:
      scrape_interval: 15s
    
    scrape_configs:
      - job_name: 'taskflow'
        metrics_path: '/actuator/prometheus'
        static_configs:
          - targets: ['host.docker.internal:8080']
    
  9. 9
    Grafana dashboard
    1. http://localhost:3000 → admin/admin
    2. Data Sources → Add → Prometheus → http://prometheus:9090
    3. Import dashboard ID 11378 (Spring Boot) — готовые графики

    ---

🎯

Зачем это на собесе

После урока ты должен уметь ответить на:

«Я не знаю что в проде» → теперь знаешь: JVM heap, GC, latency p95, ошибки, активные соединения.
Алерты: Prometheus + Alertmanager → Slack/Telegram «taskflow.http.errors.rate > 5%».
HPA в K8s: kubectl autoscale deployment taskflow --cpu-percent=70 --min=2 --max=10 — на основе метрик CPU/RAM из Prometheus.
Liveness/Readiness для K8s: если приложение зависло — K8s его убьёт и перезапустит.

5 вопросов на углубление

Раскрой вопрос и нажми «🤔 Хочу разобрать подробнее» — он попадёт в страницу ответов.

1
Что даёт Spring Boot Actuator?

Разбор внутри: production endpoints для health, metrics и диагностики.

2
Как работает /actuator/health?

Разбор внутри: readiness/liveness, БД и load balancer/Kubernetes.

3
Micrometer и metrics — как это связано?

Разбор внутри: фасад метрик и экспорт в Prometheus.

4
Почему нельзя открывать все actuator endpoints?

Разбор внутри: exposure.include, env/beans/configprops и безопасность.

5
Что такое health groups?

Разбор внутри: readiness и liveness для разных сценариев проверки.

Готов идти дальше?

Выбери вопросы, которые тебе интересны, и изучи их. Потом — к следующему уроку.

🚀 Перейти к Уроку 22

Сначала пройди все секции и выбери хотя бы 1 вопрос

⬅️ Назад к Уроку 20
🎉
Новый тир
Новый тир достигнут!