Опирается на правила:
R-OBS-HC-1…R-OBS-HC-3иR-OBS-HC-X1…R-OBS-HC-X3из Observability Style Guide → раздел 4. Health checks.
Важно знать
- Liveness и readiness — разные probes, разные семантики, разные dependencies.
/actuator/health/liveness— UP пока процесс отвечает. Не должен зависеть от внешних систем./actuator/health/readiness— UP когда сервис готов принимать трафик: БД подключена, dependencies прогреты.- Custom HealthIndicator для критичных внешних систем — с TTL-кешем, чтобы probe не дудосила сам сервис.
/actuator/infoсодержитgit.commit.id,build.version,build.time— для отладки версии в проде.- Health — техническое состояние, не бизнес.
orderCount > N→ DOWN — антипаттерн.- Liveness не зависит от DB: иначе K8s рестартует pod в loop при кратковременной недоступности.
Health checks — то, на что смотрит Kubernetes, ALB и load balancer, решая «дать ли трафик в этот pod». Неправильно настроенные probes — главный источник cascading failure: одна реплика DB лагает → все pods unhealthy → весь сервис недоступен.
Liveness vs Readiness
R-OBS-HC-1: Spring Boot Actuator поддерживает оба типа probe из коробки.
management:
endpoint:
health:
probes:
enabled: true
show-details: always
health:
livenessstate:
enabled: true
readinessstate:
enabled: true
После этого доступны два endpoint-а:
| Endpoint | Что проверяет | Что делает K8s |
|---|---|---|
/actuator/health/liveness | Процесс не deadlocked, JVM отвечает | UP → продолжать; DOWN → рестартует pod |
/actuator/health/readiness | Сервис готов принимать трафик: БД, прогрев | UP → шлёт трафик; DOWN → снимает из Service endpoints |
Семантическое различие критично:
- Если БД недоступна 5 секунд — readiness должен стать DOWN (трафик уйдёт на другие реплики), liveness должен остаться UP (рестарт pod-а не поможет, БД всё та же).
- Если deadlock в JVM — liveness DOWN, K8s убивает pod, новый стартует с чистым thread pool.
K8s манифест:
spec:
containers:
- name: order-service
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8081
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8081
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 2
Порт 8081 — отдельный management port (management.server.port), не business 8080. Это позволяет ограничить /actuator/* сетевой политикой.
Custom HealthIndicator с TTL-кешем
R-OBS-HC-2: для каждой критичной внешней системы — отдельный HealthIndicator (см. R-RES-HC-1). Чтобы probe не делала десятки запросов к provider'у каждые 5 секунд — TTL-кеш (см. R-RES-HC-2).
@Component
@RequiredArgsConstructor
public class PaymentProviderHealthIndicator implements HealthIndicator {
private final PaymentProviderClient client;
private final AtomicReference<CachedHealth> cache = new AtomicReference<>();
private static final Duration TTL = Duration.ofSeconds(10);
@Override
public Health health() {
var cached = cache.get();
if (cached != null && cached.expiresAt().isAfter(Instant.now())) {
return cached.health();
}
var health = checkProvider();
cache.set(new CachedHealth(health, Instant.now().plus(TTL)));
return health;
}
private Health checkProvider() {
try {
client.ping();
return Health.up().withDetail("provider", "sber").build();
} catch (Exception e) {
return Health.down(e).withDetail("provider", "sber").build();
}
}
private record CachedHealth(Health health, Instant expiresAt) {}
}
Без TTL-кеша: K8s проверяет readiness каждые 5 секунд × 10 реплик × HealthIndicator дёргает provider → 20 ping/s на provider только от health-check. На провайдере rate-limit срабатывает, реальные запросы фейлятся, readiness становится DOWN, начинается cascading.
Auto-индикаторы (DataSourceHealthContributor для DB, RedisHealthIndicator для Redis) работают из коробки и сами дёшевые.
/actuator/info с git и build info
R-OBS-HC-3: ставим в Gradle git-commit-id-plugin, дописываем в application.yml:
management:
info:
git:
mode: full
build:
enabled: true
info:
service:
name: ${spring.application.name}
В результате /actuator/info отдаёт:
{
"git": {
"commit": {
"id": "5380f21abc...",
"time": "2026-05-25T22:24:00Z"
},
"branch": "main"
},
"build": {
"version": "1.4.2",
"time": "2026-05-25T22:25:30Z",
"artifact": "order-service"
},
"service": {
"name": "order-service"
}
}
Без этого endpoint каждый инцидент начинается с вопроса «какая версия в проде сейчас» и поиска через CI/CD логи.
Что запрещено
Business-state в health check
R-OBS-HC-X1: «если pending заказов > 1000 → DOWN». Это бизнес-метрика, не техническое здоровье. Health-probe в DOWN → K8s снимает реплику из Service endpoints → меньше реплик обрабатывают накопившиеся заказы → ещё хуже.
Бизнес-метрики мониторятся отдельно через Prometheus + alerting (см. SLO). Health — только техническое: процесс жив, dependencies доступны.
Liveness зависит от внешних систем
R-OBS-HC-X2: классическая ловушка.
// КАТАСТРОФА — liveness вернёт DOWN при недоступности DB
@Component
public class CustomLivenessIndicator implements HealthIndicator {
public Health health() {
try {
jdbcTemplate.execute("SELECT 1");
return Health.up().build();
} catch (Exception e) {
return Health.down(e).build();
}
}
}
Сценарий: PG лагает 30 секунд из-за VACUUM FULL. Liveness DOWN → K8s убивает pod → новый стартует, та же DB лагает → DOWN → убивает → loop. Все реплики падают за минуту, сервис недоступен.
Liveness обязан зависеть только от самого процесса (JVM, thread pool, disk). Внешние dependencies — только в readiness.
Health-probe делает business-операцию
R-OBS-HC-X3: «давайте в probe попробуем создать тестовый заказ и удалить». Каждые 5 секунд × 10 реплик = ddos самих себя. См. R-RES-HC-X2.
Probe — light: SELECT 1, ping, cached value. Не business work.
Что запрещено — таблица
| Антипаттерн | Правило | Что взамен |
|---|---|---|
| Business-state в health check | R-OBS-HC-X1 | техническое состояние; бизнес → SLO |
| Liveness зависит от DB/Redis/external | R-OBS-HC-X2 | только readiness зависит от внешних |
| Probe делает business-операцию | R-OBS-HC-X3 | light probe (ping, cached) |
| HealthIndicator без TTL-кеша | R-OBS-HC-2 | TTL 5-30 секунд |
/actuator/health показывает details публично | R-OBS-HC-1 | show-details: when-authorized или internal-only |
Нет /actuator/info с git+build | R-OBS-HC-3 | git-commit-id-plugin + management.info.* |
Куда дальше
- Observability → раздел 4. Health checks — нормативные формулировки.
- Configuration — management port, exposed endpoints.
- Resilience → health checks —
HealthIndicatorper-system, TTL. - Metrics — бизнес-метрики мониторятся через Prometheus, не health.
- SLO и алерты — бизнес-цели отдельно от probes.
- Graceful shutdown — readiness DOWN при SIGTERM, drain in-flight.