Как сервис узнает о недоступности интеграционного компонента, например базы данных
Что проверяют
Понимаете ли вы, что о падении базы сервис узнаёт двумя путями: по ошибкам в живых запросах и по активным проверкам. И умеете ли не превратить это знание в каскадный сбой. Следом почти всегда спрашивают, включать ли базу в liveness-пробу Kubernetes.
Как отвечать
Пассивный путь срабатывает первым. Запрос берёт соединение из пула HikariCP, и если база не отвечает, через connectionTimeout (по умолчанию 30 секунд) приходит SQLTransientConnectionException. Уже открытые соединения рвутся с SQLException от драйвера. Чтобы узнать об этом быстро, а не через минуты ожидания TCP, нужны явные таймауты:
- в пуле:
connectionTimeoutиvalidationTimeoutв HikariCP; - в драйвере:
connectTimeoutиsocketTimeoutв JDBC-URL PostgreSQL; - на запрос:
@Transactional(timeout = ...)илиStatement.setQueryTimeout.
Активный путь: Spring Boot Actuator и DataSourceHealthIndicator, который проверяет соединение через Connection.isValid() или validation query и отдаёт статус в /actuator/health. В Kubernetes есть отдельные группы /actuator/health/liveness и /actuator/health/readiness. Базу можно добавить в readiness, чтобы под перестал получать трафик, но не в liveness.
Дальше реакция: Circuit Breaker из Resilience4j после порога ошибок размыкается и отвечает сразу, не держа потоки. Метрики Micrometer (hikaricp_connections_pending, hikaricp_connections_timeout_total) уходят в Prometheus, и алерт срабатывает раньше, чем начнут жаловаться пользователи.
Где спотыкаются
Кладут базу в liveness-пробу. База упала, Kubernetes перезапускает все поды разом, а перезапуск базу не чинит и только добавляет шторм переподключений.
Не ставят таймауты. Потоки висят на мёртвом сокете, пул и потоки Tomcat заканчиваются, и сервис перестаёт отвечать даже на запросы, которым база не нужна.
Повторяют запросы без паузы и джиттера. Восстанавливающаяся база получает всплеск нагрузки и падает снова, а повтор неидемпотентной записи создаёт дубли.