Health check эндпоинты: где отказ ломает весь сервис
Отказ одного узла редко остаётся локальным. Балансировщик продолжает слать трафик на инстанс, который уже не может обслуживать запросы — соединения копятся, пул потоков исчерпывается, и через несколько минут ложится весь сервис. Это классический каскадный отказ: health check эндпоинты либо отсутствуют, либо отвечают «ок» независимо от реального состояния приложения.
Обратная крайность не лучше. Если liveness проба проверяет внешнюю зависимость — базу, очередь, сторонний API — то при кратковременной недоступности базы платформа начнёт перезапускать здоровые инстансы. Получаем ложные перезапуски: сервис теряет соединения, прогревает кеш заново, а причина сбоя никуда не делась. Разделение проб снимает эту путаницу: liveness отвечает только за «процесс жив и не завис», readiness — за «готов принимать трафик прямо сейчас».
Readiness проба — это точка, где трафик отсекается до того, как пользователь увидит ошибку. Пока инстанс прогревает кеш, ждёт миграции или теряет связь с базой, он честно сообщает «не готов» — балансировщик выводит его из ротации, и запросы уходят на рабочие узлы. Без этого механизма деградация одного пода превращается в простой сервиса для всех.
Цена ошибки измерима: при корректных пробах время восстановления после сбоя узла — секунды, при их отсутствии — минуты, пока дежурный вручную не выведет инстанс. Дальше разбираем, как это закрывается на уровне конфигурации.
Что даёт правильно настроенный health check
Время восстановления падает с десятков минут до секунд
Liveness-проба перестаёт быть формальностью: она проверяет не «процесс жив», а способность сервиса отвечать на реальный запрос — доступность пула соединений с базой, состояние внутренних очередей, готовность кеша. Когда контейнер зависает в деградированном состоянии, оркестратор получает честный сигнал и перезапускает его сразу, а не через полчаса по алерту от дежурного. На практике это разница между восстановлением за 20-40 секунд и ручным разбором на 15-30 минут.
Ложные перезапуски уходят из графика дежурств
Readiness-проба с корректными порогами (задержка старта, число допустимых провалов, период опроса) отделяет «сервис ещё поднимается» от «сервис сломан». Без неё типична картина: приложение стартует дольше таймаута, оркестратор убивает его на середине инициализации, цикл повторяется — сервис не выходит в строй вообще. Правильная конфигурация убирает этот класс инцидентов полностью, а вместе с ним — ночные перезапуски и ложные срабатывания мониторинга.
Маршрутизация трафика перестаёт слать запросы в мёртвые поды
Пока readiness не подтверждена, балансировщик не направляет трафик на экземпляр — и наоборот, при провале пробы убирает его из ротации до перезапуска. Это закрывает отказы, которые иначе выглядят как случайные ошибки у части пользователей: запросы уходят в контейнер, который уже не обслуживает соединения. Доступность сервиса перестаёт зависеть от того, успел ли кто-то вручную убрать узел.
Разделение проб даёт управляемый откат
Когда liveness, readiness и стартовая проба настроены раздельно, перезапуск перестаёт быть единственной реакцией на любой сбой. Временная потеря базы валит readiness, но не убивает контейнер — сервис пережидает сбой и возвращается в ротацию сам. Это снижает нагрузку на инфраструктуру и сохраняет состояние, которое теряется при жёстком рестарте.
Подходы к проверке состояния: сравнение режимов
Проверки делятся на два уровня: внутренние пробы оркестратора, которые решают, перезапускать ли контейнер и пускать ли на него трафик, и внешний мониторинг, который смотрит на сервис глазами пользователя. Смешивать их нельзя: проба, дергающая базу или внешний API, при сбое зависимости уронит здоровый под, а мониторинг, стучащийся только в корень сайта, не увидит, что приложение отдаёт ошибки на половине сценариев.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Liveness-проба | Процесс может зависнуть: дедлок, зацикливание, исчерпание пула потоков | Отвечает только «жив ли процесс». Зависимости не проверяет — иначе каскадный перезапуск всего сервиса при сбое базы |
| Readiness-проба | Нужно убрать под из балансировки на время прогрева, миграций или перегрузки | Не перезапускает контейнер. При ошибке в логике легко получить под, вечно висящий вне трафика |
| Startup-проба | Долгий старт: прогрев кеша, загрузка моделей, применение миграций | Работает один раз за жизнь контейнера. Если старт нестабилен по времени — порог придётся поднимать с запасом |
| Внешний мониторинг | Проверка сквозного сценария: вход, оплата, отдача данных из хранилища | Не управляет оркестратором. Ложные срабатывания при сетевых всплесках, нужен запас по частоте опроса |
На практике режимы комбинируют: startup закрывает долгий запуск, readiness регулирует трафик, liveness ловит зависания, а внешний мониторинг подтверждает, что сервис работает для клиента. Разделение эндпоинтов — обязательное условие: /healthz для процесса и /ready для готовности принимать запросы не должны ходить в одни и те же зависимости.
Главное ограничение любого режима — цена ложного срабатывания. Слишком строгая liveness-проба превращает кратковременную просадку в шторм перезапусков, слишком мягкая — оставляет нерабочий под в ротации. Поэтому пороги, задержки и число повторов подбирают под реальный профиль нагрузки, а не по умолчанию.
Этапы внедрения health check эндпоинтов
Внедрение health check эндпоинтов начинается с аудита того, что уже есть: какие проверки отвечают на запросы, что именно они проверяют и как на них реагирует балансировщик. Часто выясняется, что эндпоинт возвращает «ок» всегда — при недоступной базе или переполненной очереди он всё равно отдаёт успешный ответ, и трафик продолжает идти на сломанный экземпляр. На этом этапе фиксируем зависимости сервиса и договариваемся, отказ какой из них должен выводить экземпляр из ротации, а какой — только сигнализировать.
- Аудит текущих проверок. Собираем список эндпоинтов, смотрим, что они проверяют, как настроены интервалы и пороги на стороне оркестратора, какие сбои уже приводили к простоям.
- Проектирование схемы проверок. Разделяем liveness и readiness: первая отвечает на вопрос «жив ли процесс», вторая — «готов ли он принимать трафик». Отдельно проектируем проверку старта для сервисов с долгой инициализацией, чтобы проба не убивала экземпляр раньше времени.
- Настройка проб. Прописываем интервалы, таймауты, количество повторов до перевода в состояние отказа и пороги, при которых экземпляр выводится из ротации. Проверки делаем дешёвыми — без тяжёлых запросов к базе, чтобы проба сама не создавала нагрузку.
- Тестирование сценариев отказа. Намеренно роняем зависимость, забиваем очередь, отзываем доступ к хранилищу — и смотрим, как ведёт себя система: уходит ли трафик с проблемного экземпляра, восстанавливается ли он после возврата зависимости, нет ли ложных срабатываний при кратковременных сбоях.
- Документация. Передаём схему проверок, значения параметров и логику реакции на отказ — чтобы дежурный инженер понимал, почему экземпляр вышел из ротации, и мог отличить реальную аварию от ложного срабатывания.
После внедрения отказ одного экземпляра перестаёт быть заметен для пользователя: трафик уходит на здоровые узлы, а восстановление происходит без ручного вмешательства. Опишите вашу задачу — вернёмся с оценкой и планом работ.
Артефакты и конфигурации, которые вы получаете
По итогу работ вы получаете не «настроенный мониторинг», а воспроизводимый набор артефактов: конфигурации, схемы, политики и регламенты, по которым система живёт и передаётся вашей команде без устных пояснений. Ниже — что именно остаётся в репозитории и в документации.
- Конфигурация проб — манифесты с liveness, readiness и startup-проверками: путь эндпоинта, интервалы, пороги отказов, задержка первого запуска. Отдельно для каждого сервиса, с комментариями, почему выбраны такие значения.
- Схема зависимостей — карта, какой сервис от кого зависит и как это отражено в readiness: проверка БД, очереди, внешних API. Видно, что именно блокирует приём трафика при сбое.
- Политики доступа — правила, кто и откуда может дёргать эндпоинты: внутренняя сеть, оркестратор, системы мониторинга. Публичный доступ закрыт, проверки не светят состояние сервиса наружу.
- Регламенты реагирования — что означает каждый статус пробы, при каком сценарии перезапуск, при каком — снятие с балансировки, кому уходит оповещение и в какой срок.
- Инструкции по эксплуатации — как добавить новую пробу, изменить порог, откатить конфигурацию. С примерами правок и ожидаемым результатом.
- Набор тестовых сценариев — как воспроизвести отказ: погасить зависимость, замедлить ответ, уронить процесс. Проверка, что пробы реагируют так, как задумано.
- Отчёт по внедрению — какие сервисы покрыты, какие пороги выставлены, что осталось за рамками и почему.
Конфигурации лежат в системе контроля версий рядом с кодом сервисов — изменения проходят ревью и попадают в историю. Схемы и регламенты — в документации проекта, в формате, который читается без доступа к инфраструктуре. Опишите вашу задачу — вернёмся с оценкой и планом, какие артефакты нужны именно вам.
Кейс: как health check эндпоинты сократили простои
Проект — высоконагруженный сервис с очередью фоновых задач: несколько инстансов за балансировщиком, деплой по нескольку раз в неделю. До внедрения проверок контейнеры перезапускались по внешнему признаку «процесс жив», хотя приложение уже не отвечало: пул соединений к базе исчерпан, фоновые обработчики встали, но процесс не падал. Балансировщик продолжал слать трафик на нездоровый инстанс, клиенты получали ошибки, а дежурный узнавал о сбое из обращений. Каждый такой инцидент растягивался на десятки минут ручной диагностики.
Что изменили
Развели два типа проверок по смыслу. Liveness отвечает только на вопрос «процесс завис намертво» — если да, платформа перезапускает контейнер. Readiness описывает готовность принимать трафик: доступность базы, наполненность пула соединений, состояние фоновых обработчиков. Пока readiness не проходит, инстанс выводится из балансировки, но не убивается — это принципиально, иначе перезапуск во время прогрева даёт лавину.
Отдельно настроили стартовую проверку с увеличенным окном: приложение прогревает кеши и поднимает соединения дольше, чем длится обычный интервал, и без этого платформа убивала контейнер до готовности. Пороги подобрали так, чтобы единичный сбой зависимости не выводил инстанс из строя, а устойчивая деградация — выводила.
Что стало
Kubernetes перестал перезапускать здоровые контейнеры и начал убирать из балансировки только реально неготовые. Доля запросов, попавших на нездоровый инстанс, упала с 4–5% до долей процента. Среднее время восстановления после сбоя зависимости сократилось с десятков минут до 1–2: инстанс сам возвращается в строй, как только readiness снова проходит. Число перезапусков контейнеров за неделю снизилось примерно в пять раз — ушли ложные срабатывания на прогреве и пиковой нагрузке.
Стабильность перестала зависеть от того, заметил ли дежурный проблему. Проверки фиксируют деградацию раньше, чем её почувствуют клиенты, а метрики по эндпоинтам дают готовую картину для разбора.
Чем отличается liveness от readiness?
Liveness отвечает на вопрос «жив ли процесс», readiness — «готов ли он принимать трафик». Это разные вопросы, и путать их дорого: проба, которая проверяет не то, что нужно, либо роняет здоровый под подозрением контейнер в цикл перезапусков, либо держит в балансировке экземпляр, который ещё не поднял соединения с базой.
Liveness-проба смотрит только на самочувствие самого процесса: не заблокировался ли он, не ушёл ли в дедлок, отвечает ли управляющий поток. Если проверка падает, платформа убивает контейнер и поднимает новый — это аварийный рычаг, а не инструмент тонкой настройки. Классическая ошибка — повесить в liveness проверку внешней зависимости: база моргнула на десять секунд, и весь парк контейнеров уходит в одновременный перезапуск, хотя приложение было полностью работоспособно.
Readiness-проба, наоборот, управляет маршрутизацией. Пока она не проходит, экземпляр исключён из балансировки, но продолжает жить: догружает кэш, ждёт прогрева пула соединений, применяет миграции. Упавшая readiness не перезапускает контейнер — она лишь убирает его из выдачи, и когда зависимость возвращается, экземпляр так же плавно возвращается в строй.
Отсюда практическое правило: в liveness — минимум логики, только «процесс отвечает»; в readiness — всё, без чего запрос не будет обслужен корректно. Таймауты тоже расходятся: readiness можно проверять часто и с коротким порогом, liveness — реже и с запасом, чтобы не убивать контейнер на пиковой нагрузке, когда ответы закономерно замедлились.
Частые технические сомнения
Пробы встраиваются в уже работающий сервис без переписывания бизнес-логики: добавляется отдельный эндпоинт, который проверяет зависимости и отдаёт статус. Если приложение уже развёрнуто в кластере, сначала снимаем текущее поведение — как оно отвечает при недоступной базе, при переполненном пуле соединений, при медленном внешнем сервисе. По этой картине настраиваем пороги, а не по умолчанию.
Ограничения у проб есть, и их важно проговорить до внедрения. Liveness не должен ходить в базу или внешний сервис: если зависимость моргнула, перезапуск контейнера её не вылечит, а сервис потеряет обработку запросов. Readiness, наоборот, обязан учитывать готовность зависимостей — иначе трафик пойдёт на инстанс, который ещё не может отвечать. Разделение этих ролей и есть основная работа.
Как избежать ложных срабатываний при кратковременных сбоях?
Порог срабатывания задаётся не одним запросом, а серией: например, три неудачные проверки подряд с интервалом и периодом ожидания. Плюс отдельный таймаут на сам эндпоинт — он должен отвечать быстрее, чем истекает проба. Так кратковременная задержка базы не приводит к перезапуску, а устойчивая деградация — приводит.
Что будет с уже настроенным решением, если мы придём?
Разбираем текущие пробы и смотрим, что они реально проверяют. Часто liveness и readiness указывают на один и тот же эндпоинт — это первое, что разделяем. Конфигурацию переносим в манифесты, чтобы пороги и таймауты были версионированы, а не заданы руками в панели. Откат — возврат предыдущего манифеста, без пересборки образа.
Нужно ли менять код приложения под пробы?
В большинстве случаев — нет. Эндпоинт добавляется отдельным обработчиком, бизнес-логика не затрагивается. Если сервис не умеет отдавать статус зависимостей, добавляем лёгкую проверку: доступность соединения и время ответа. Этого достаточно, чтобы проба отражала реальную готовность, а не факт запуска процесса.
Обсудим вашу задачу по настройке health check
Чтобы вернуться с оценкой и планом, а не с общими словами, нам нужен минимум вводных по вашему контуру. Опишите задачу: какие сервисы обслуживаются, как сейчас устроен деплой, есть ли оркестратор и как пробы настроены сегодня. Этого достаточно, чтобы понять объём и предложить конкретную схему.
Что полезно приложить к описанию:
- перечень сервисов и их роли — какие принимают трафик, какие работают в фоне;
- текущие манифесты или конфигурации деплоя, если они есть;
- как сейчас проверяется доступность: внешний мониторинг, ручные проверки или ничего;
- требования к времени восстановления — сколько простоя допустимо при отказе пода;
- ограничения по доступам и средам: сколько контуров, кто владелец кластера;
- известные проблемы: ложные перезапуски, зависшие поды, долгий прогрев после старта;
- контактное лицо со стороны инфраструктуры для уточнений по ходу работ.
По этому набору мы оцениваем трудозатраты, называем этапы и порядок выката. Дальше согласуем план работ: разметку проб по сервисам, настройку порогов и таймаутов, проверку на staging и поэтапный вывод в продуктив. Старт проекта — после того как зафиксируем границы и точки отката.
Опишите задачу в удобном виде — вернёмся с оценкой и планом работ.
| Подход к проверке | Что проверяет | Когда срабатывает | Риск ложного отказа | Кому подходит |
|---|---|---|---|---|
| Проверка живости процесса | Отвечает ли приложение в принципе | При полной остановке или зависании | Низкий — реагирует только на явную смерть | Сервисы без внешних зависимостей |
| Проверка готовности к трафику | Готов ли сервис принимать запросы | При прогреве, миграциях, перегрузке | Средний — зависит от настроек задержки | Сервисы с долгим стартом |
| Проверка зависимостей | Доступны ли база, кэш, очереди | При обрыве связи с внешним узлом | Высокий — чужая авария гасит ваш сервис | Только для критичных цепочек |
| Глубокий синтетический сценарий | Проходит ли реальный бизнес-путь | При деградации логики, а не связи | Высокий — дорого и хрупко | Редко, для ключевых операций |
| Комбинированная схема | Раздельно: процесс, готовность, зависимости | Точечно под каждый класс сбоя | Низкий при верных порогах | Большинство продуктовых сервисов |
| Этап | Что делаем | Результат этапа | Типовой срок |
|---|---|---|---|
| Разбор отказ | Собираем историю простоев и ложных срабатываний | Список сбоев, которые нужно ловить | 1–2 дня |
| Проектирование | Разделяем проверки по назначению и порогам | Схема эндпоинтов и правил | 2–3 дня |
| Внедрение | Пишем обработчики, подключаем к среде запуска | Работающие проверки в тестовой среде | 3–5 дней |
| Настройка порогов | Подбираем задержки, повторы, лимиты | Баланс между скоростью реакции и шумом | 2–4 дня |
| Наблюдение | Выводим метрики и оповещения | Видно, почему сервис перезапустился | 1–2 дня |
| Сопровождение | Правим пороги под рост нагрузки | Проверки не мешают при пиках | постоянно |
| Слой | Зачем в схеме проверок | Что даёт клиенту |
|---|---|---|
| Приложение | Отдаёт сигнал о своём состоянии | Сервис сам сообщает о проблеме, а не молчит |
| Среда запуска | Перезапускает и выводит из балансировки | Сбой одного экземпляра не роняет весь сервис |
| Балансировщик | Направляет трафик только на готовые узлы | Пользователь не попадает на «прогревающийся» узел |
| Мониторинг | Хранит историю и шлёт оповещения | Видно причину сбоя, а не только факт |
| Оповещения | Будит дежурного по нужному порогу | Реакция до того, как о проблеме напишут клиенты |
| Критерий выбора | Простая проверка | Расширенная проверка |
|---|---|---|
| Скорость настройки | Быстро | Дольше |
| Точность сигнала | Грубая | Высокая |
| Нагрузка на сервис | Минимальная | Заметная при частых опросах |
| Устойчивость к чужим сбоям | Высокая | Требует аккуратных порогов |
| Когда выбирать | Старт, простые сервисы | Продукт с внешними зависимостями |







