Когда приложение работает в продакшене, нужно понимать, что внутри происходит: сколько запросов обрабатывается, где задержки, что пишется в логах. Всё это называют наблюдаемостью (observability). Чтобы это работало правильно, нужно однажды настроить четыре вещи: отдельный порт для служебных endpoints, явный список того, что открыто, гистограммы задержек и формат логов. Разберём каждую.
Отдельный порт для Actuator
По умолчанию Spring Boot запускает всё на одном порту: и ваш API (/api/orders), и служебные endpoints Actuator (/actuator/health, /actuator/prometheus). Это удобно локально, но создаёт проблемы в продакшене.
Если Actuator на том же порту, что и API, сетевой политикой нельзя запретить доступ к нему извне: Kubernetes Ingress открывает порт целиком, а не отдельные пути. Prometheus scraper (который собирает метрики каждые 15 секунд) и healthcheck-зонды (каждые 5 секунд) создают нагрузку на тот же поток, что обрабатывает бизнес-запросы.
Решение простое — разные порты:
server:
port: 8080
management:
server:
port: 8081
Теперь Ingress публикует только 8080, а сетевая политика разрешает Prometheus обращаться только на 8081. Служебный трафик не мешает бизнес-логике.
Явный список открытых endpoints
Дефолт Spring Boot открывает только health и info. Когда добавляют '*', чтобы быстро посмотреть всё сразу, — открывается гораздо больше, чем нужно.
Некоторые endpoints небезопасны для публичного доступа:
/actuator/env— показывает все конфигурационные свойства, включая те, что попали туда через переменные окружения. Если секрет оказался там случайно, он будет виден./actuator/heapdump— полный дамп памяти JVM. Он может содержать JWT-токены, пароли, персональные данные пользователей, которые в данный момент обрабатываются./actuator/threaddump— стек всех потоков. Раскрывает внутреннюю структуру приложения.
Правило простое: указывать только то, что действительно нужно:
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics нужен для ручного дебага через JSON. prometheus — для scraper'а. Остальное закрыто.
Если очень нужен heapdump в продакшене для отладки — Spring Security с ролью администратора и аудит каждого обращения. По умолчанию — не открывать.
Гистограммы задержек и SLO buckets
Стандартная метрика http.server.requests в Micrometer по умолчанию считает только количество запросов и суммарное время. Чтобы знать, сколько запросов уложились в 500 мс или какой p95, нужна гистограмма.
management:
metrics:
distribution:
percentiles-histogram:
http.server.requests: true
slo:
http.server.requests: 100ms,500ms,1s,5s
tags:
service: ${spring.application.name}
env: ${ENV:dev}
version: ${BUILD_VERSION:unknown}
percentiles-histogram: true заставляет Micrometer публиковать полную гистограмму (~64 bucket'а). В Prometheus это позволяет посчитать точный квантиль через histogram_quantile() — без интерполяции.
slo: 100ms,500ms,1s,5s добавляет явные пороговые bucket'ы. В Prometheus появится метрика http_server_requests_seconds_bucket{le="0.5"} — «сколько запросов завершилось быстрее 500 мс». Это удобно для SLO-алертов: больше не нужно интерполировать.
tags.service/env/version — глобальные метки, которые добавятся ко всем метрикам автоматически. Без них непонятно, от какого сервиса и окружения пришли данные. BUILD_VERSION проставляется из CI как переменная окружения.
Два профиля логирования
В разработке удобны однострочные читаемые логи. В продакшене нужен структурированный JSON, который Logstash или Vector умеют парсить и индексировать.
Logback поддерживает Spring-профили прямо в logback-spring.xml:
<configuration>
<springProfile name="dev,test">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level [%thread] %X{traceId:-} %logger{30} - %msg%n</pattern>
</encoder>
</appender>
</springProfile>
<springProfile name="prod,staging">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>traceId</includeMdcKeyName>
<includeMdcKeyName>spanId</includeMdcKeyName>
<includeMdcKeyName>requestId</includeMdcKeyName>
<includeMdcKeyName>userId</includeMdcKeyName>
</encoder>
</appender>
</springProfile>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
springProfile — это расширение Logback, которое Spring Boot активирует при запуске. Нужный appender включается в зависимости от профиля.
В dev-паттерне %X{traceId:-} берёт traceId из MDC и подставляет в строку лога. Если трейсинг не настроен — пустая строка, ничего не падает. По этому идентификатору потом ищут запрос в Tempo или Jaeger.
В продакшене LogstashEncoder пишет каждую строку как JSON-объект. MDC-поля, перечисленные в <includeMdcKeyName>, попадают в JSON явно. Остальные ключи MDC — в блок mdc автоматически.
Частые ошибки
Один порт для API и Actuator в продакшене. Сетевую изоляцию сделать не получится. management.server.port: 8081 решает проблему.
exposure.include: '*'. Открывает env, beans, mappings, loggers, configprops, heapdump. Каждый из них — потенциальная утечка данных. Явный список надёжнее:
# так не надо
management.endpoints.web.exposure.include: '*'
# так правильно
management.endpoints.web.exposure.include: health,info,metrics,prometheus
Один Logback-паттерн для dev и prod. В разработке теряется читаемость JSON, в продакшене теряется структура. springProfile — стандартный способ разделить.
Нет гистограммы для метрик задержки. Тогда квантили либо не считаются, либо только примерные. percentiles-histogram: true для http.server.requests — минимальный набор.
Коротко
- Запускайте Actuator на отдельном порту (
management.server.port: 8081) — это даёт сетевую изоляцию и не мешает бизнес-трафику. - Явно перечисляйте открытые endpoints:
health,info,metrics,prometheus. Wildcard'*'— источник утечек. /actuator/env,/actuator/heapdump,/actuator/threaddumpне открывают публично — они содержат секреты и дампы памяти.percentiles-histogram: true+slo: 100ms,500ms,1s,5sдляhttp.server.requests— основа для SLO-алертов на задержку.- Глобальные теги
service/env/versionвmanagement.metrics.tagsсразу расставляют контекст по всем метрикам. - Два профиля в
logback-spring.xml: текстовый дляdev,test, JSON черезLogstashEncoderдляprod,staging.
Что почитать дальше
- Логирование в Java — structured JSON, MDC, уровни
- Метрики — Micrometer, Prometheus, RED/USE
- Трассировка — OpenTelemetry, traceparent, sampling
- Health checks — liveness, readiness, custom HealthIndicator
- SLO и алерты — error budget и burn rate