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Зависимости
dependencies { implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("io.micrometer:micrometer-registry-prometheus") } -
2application.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 # В продакшене лучше отдельный порт (см. ниже) -
3Endpoints
# 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Пример вывода
/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 -
5Custom метрики
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Использование в
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Отдельный порт для Actuator (безопасность)
management: server: port: 9090 # отдельный порт, доступ только изнутри K8s address: 127.0.0.1 # слушает только localhostТогда
/actuator/prometheusдоступен наlocalhost:9090, основной API — на:8080. -
8Docker 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'] -
9Grafana dashboard
- http://localhost:3000 → admin/admin
- Data Sources → Add → Prometheus → http://prometheus:9090
- Import dashboard ID
11378(Spring Boot) — готовые графики
---
Зачем это на собесе
После урока ты должен уметь ответить на:
taskflow.http.errors.rate > 5%».kubectl autoscale deployment taskflow --cpu-percent=70 --min=2 --max=10 — на основе метрик CPU/RAM из Prometheus.5 вопросов на углубление
Раскрой вопрос и нажми «🤔 Хочу разобрать подробнее» — он попадёт в страницу ответов.
Разбор внутри: production endpoints для health, metrics и диагностики.
Разбор внутри: readiness/liveness, БД и load balancer/Kubernetes.
Разбор внутри: фасад метрик и экспорт в Prometheus.
Разбор внутри: exposure.include, env/beans/configprops и безопасность.
Разбор внутри: readiness и liveness для разных сценариев проверки.
Готов идти дальше?
Выбери вопросы, которые тебе интересны, и изучи их. Потом — к следующему уроку.
🚀 Перейти к Уроку 22Сначала пройди все секции и выбери хотя бы 1 вопрос
⬅️ Назад к Уроку 20