Балансировщик, который проверяет только код ответа, рано или поздно отправит клиента на узел, где приложение отвечает 200, а база данных уже недоступна. Классический health-check по HTTP-200 ловит падение процесса, но пропускает деградацию: пул соединений к PostgreSQL исчерпан, Redis недоступен, внешний платежный шлюз не отвечает, а веб-сервер бодро возвращает страницу-заглушку. Именно поэтому настройка балансировки по бизнес-эндпоинту, а не по формальному коду ответа, становится обязательным этапом при построении отказоустойчивой ИТ-инфраструктуры.
Логика простая: health-check должен отвечать на вопрос “может ли этот узел прямо сейчас обслужить реальный пользовательский запрос”, а не “жив ли процесс”. Если узел не может записать заказ в БД или отдать данные из кэша, трафик на него идти не должен, даже если TCP-порт открыт и nginx отдает 200. В статье разберем пошаговый переход от примитивной проверки к бизнес-эндпоинту: какие зависимости включать, как выставить таймауты и пороги, чтобы не выбить живой узел из пула на коротком всплеске, и как протестировать отказоустойчивость до того, как это сделает прод. Отдельно разберем, чем заменить Cloudflare в России, если нужен балансировщик с кастомными health-check: российский аналог Cloudflare вроде TrafficVeil закрывает DNS, SSL, reverse proxy, WAF и L7 DDoS в одном контуре, а логику проверок можно привязать к собственному эндпоинту.
Ниже – рабочие примеры для nginx и HAProxy, критерии выбора эндпоинта и методика проверки, которая показывает реальную картину отказа, а не красивый график аптайма.
Почему HTTP-200 недостаточен для health-check в отказоустойчивой балансировке
Балансировщик, который проверяет только код ответа, защищает от самого простого класса отказов: упал процесс, закрылся порт, сервер выключили. Как только отказ становится частичным, проверка по HTTP-200 превращается в источник ложной уверенности. Узел отвечает 200, балансировщик считает его здоровым и продолжает лить туда трафик, а бизнес-операция на этом узле не выполняется.
Типичный сценарий: веб-сервер жив, статика отдаётся, страница логина рендерится. Но пул соединений к PostgreSQL исчерпан, и любой запрос, который трогает базу, возвращает 500 или, что хуже, зависает до таймаута. Проверка вида GET / HTTP/1.1 с ожиданием 200 ничего не заметит. То же самое с Redis: если кэш недоступен, а приложение спроектировано так, что без него не собирает корзину, пользователь видит ошибку, а балансировщик видит здоровый узел.
Разберём, что именно маскирует код 200.
- Недоступность БД. Приложение отдаёт кэшированную или статическую заглушку на главной, но транзакции не проходят. Проверка по корню сайта проходит, оформление заказа падает.
- Отказ внешних сервисов. Платёжный шлюз, SMS-провайдер, сервис доставки, 1С по API. Узел формально работает, но ключевой бизнес-процесс не завершается.
- Переполнение диска или исчерпание inode. Запись в лог или сессию не идёт, чтение ещё работает. HTTP-200 на GET есть, POST с сохранением данных ломается.
- Деградация пула воркеров. Все PHP-FPM или Gunicorn-процессы заняты долгими запросами. Новые соединения встают в очередь, health-check по лёгкому эндпоинту отвечает мгновенно и успешно.
- Проблемы с правами и конфигурацией. После деплоя не подхватился новый конфиг, приложение работает в режиме read-only, но 200 отдаёт.
Цена такой слепоты измерима. Если из четырёх узлов два отвечают 200, но не могут писать в БД, балансировщик отправляет на них половину трафика. Конверсия сайта падает пропорционально доле сломанных узлов, а метрики доступности остаются зелёными, потому что мониторинг смотрит на тот же код ответа. Инцидент обнаруживается не по алерту, а по звонкам клиентов или падению числа заказов. Для интернет-магазина на Bitrix или WordPress это прямые потери в лидогенерации, которые можно было предотвратить.
Отдельная проблема, характерная для российского контура: часть зависимостей находится за границей или за сегментом, доступность которого нестабильна. Узел может отвечать 200 на локальный запрос и одновременно не иметь доступа к внешнему API. Классический health-check этого не различает, потому что не знает, что для бизнеса этот API критичен. Российские интернет-провайдеры ограничивают доступ к сайтам на Cloudflare, и если часть вашей инфраструктуры завязана на зарубежные сервисы, картина усложняется: отказ приходит не от вашего сервера, а от маршрута до зависимости.
Вывод простой: код ответа описывает состояние HTTP-слоя, а не состояние бизнес-функции. Отказоустойчивая балансировка должна проверять то, что реально приносит деньги и обслуживает пользователя, то есть бизнес-эндпоинт, который дергает базу, кэш и критичные внешние сервисы. Дальше разберём, как выбрать такой эндпоинт и не уйти в другую крайность, когда проверка сама становится источником ложных отказов.
Выбор бизнес-эндпоинта для health-check: критерии и примеры
Код 200 от веб-сервера означает ровно одно: процесс принял TCP-соединение и отдал шапку ответа. Он ничего не говорит о том, доступна ли база, живы ли Redis и очередь, не отвалился ли внешний платежный шлюз. Балансировщик, который верит голому 200, продолжает лить трафик на узел, где закешированная главная отдается из памяти, а корзина и оформление заказа падают с 500. Для интернет-магазина это потерянные заказы, для SaaS – рост оттока. Разберем, как выбрать эндпоинт, который отвечает за реальную работоспособность приложения.
Что именно должен проверять бизнес-эндпоинт
Хороший health-эндпоинт повторяет критический путь пользователя, но без побочных эффектов. Практический набор проверок для среднего проекта:
- База данных. Простой
SELECT 1или чтение строки из служебной таблицы с таймаутом 200-500 мс. Не запускайте тяжелые аналитические запросы: health-check дергается каждые 2-5 секунд и сам станет нагрузкой. - Кэш и сессии. PING к Redis или Memcached. Если сессии лежат в Redis, а он недоступен, авторизованные пользователи получат разлогин.
- Очередь задач. Проверка соединения с брокером, но без публикации реальных сообщений.
- Критичные внешние API. Платежи, SMS, доставка. Тут осторожно: чужой сервис может лежать 10 минут, и вы снимете с балансировки весь пул. Ставьте такие проверки в отдельный необязательный блок.
- Свободное место и лимиты. Если диск заполнен на 98%, узел формально жив, но скоро упадет. Порог лучше вынести в отдельный алерт, а не в health-check.
Критерии выбора и защита от ложных срабатываний
Эндпоинт должен быть дешевым, детерминированным и разделять состояния. Базовый шаблон ответа: 200 – узел здоров, 503 – узел не должен получать трафик. Промежуточные коды не используйте, балансировщики трактуют их по-разному.
Формат JSON с разбивкой по зависимостям упрощает диагностику: {"db":"ok","redis":"ok","queue":"degraded"}. Тогда правило можно сформулировать как “нездоров, если db или redis не ok”, а degraded по очереди игнорировать.
Ложные срабатывания почти всегда дают три причины. Первая – таймаут проверки меньше, чем реальное время ответа под нагрузкой. Ставьте таймаут 2-3 секунды при нормальном отклике 50-150 мс, это запас на пики. Вторая – проверка ходит через тот же пул соединений, что и пользовательский трафик, и захлебывается вместе с ним. Выделите отдельный пул или отдельного пользователя БД с минимальными правами. Третья – каскадный отказ: упал общий Redis, и балансировщик разом вывел все узлы. Здесь помогает порог: unhealthy после 3 подряд неудачных проверок при интервале 5 секунд, healthy после 2 успешных.
Отдельно про GeoIP-фильтрацию и WAF: не смешивайте их с health-check. Блокировка ботов и L7 DDoS живут на уровне правил, а не доступности бэкенда, иначе легитимный скачок трафика из одного региона выключит вам половину пула.
И последнее: эндпоинт не должен требовать авторизации, но и не должен отдавать внутренние детали наружу. Ограничьте доступ по IP балансировщика или отдавайте только агрегированный статус без версий и путей. Если сайт работает на WordPress или Bitrix, добавьте в /health проверку соединения с их БД отдельно от проверки самого PHP-процесса: CMS часто отвечает 200 из кэша плагина при мертвой базе.
Пошаговая настройка health-check по бизнес-эндпоинту в балансировщике
Начнём с эндпоинта. Создайте на каждом бэкенде отдельный маршрут, который проверяет не факт запуска процесса, а способность приложения выполнить реальную работу: открыть соединение с БД, прочитать одну строку из справочника, проверить доступность кэша и внешнего API. Для WordPress это может быть скрипт, дергающий $wpdb->get_var(“SELECT 1”) и проверку записи в object cache; для Bitrix – вызов \Bitrix\Main\Application::getConnection()->queryScalar(“SELECT 1”). Отдавайте ответ только после всех проверок: 200 при полном успехе, 503 при любой неудаче. Время выполнения держите в пределах 50-150 мс, иначе health-check сам станет источником нагрузки.
Дальше – конфигурация балансировщика. В nginx (open source) активные проверки недоступны, поэтому используем пассивные: модуль upstream с параметрами max_fails и fail_timeout. Пример для пула из трёх узлов:
upstream backend {
server 10.0.0.11:8080 max_fails=2 fail_timeout=10s;
server 10.0.0.12:8080 max_fails=2 fail_timeout=10s;
server 10.0.0.13:8080 max_fails=2 fail_timeout=10s;
}
Здесь max_fails=2 означает: два ответа 5xx или таймаута за fail_timeout=10s выводят узел из ротации на 10 секунд. Дополнительно задайте proxy_next_upstream error timeout http_502 http_503, чтобы клиент не видел ошибку, и proxy_connect_timeout 2s, proxy_read_timeout 5s.
В HAProxy логика богаче – есть активные проверки. Конфигурация для того же пула:
backend app_servers
option httpchk GET /health/business
http-check expect status 200
default-server inter 3s fall 2 rise 2 timeout 2s
server s1 10.0.0.11:8080 check
server s2 10.0.0.12:8080 check
server s3 10.0.0.13:8080 check
Ключевые параметры: inter 3s – интервал опроса, fall 2 – число неудач до вывода из ротации, rise 2 – число успехов до возврата, timeout 2s – предел ожидания ответа. Порог fall=2 при интервале 3 секунды даёт суммарную задержку обнаружения около 6 секунд: достаточно быстро, чтобы не терять трафик, и достаточно мягко, чтобы не срабатывать на единичном сетевом всплеске.
Привязка к пулу выполняется через server … check в том же backend. Если у вас несколько пулов (например, отдельно для API и для отдачи статики), заведите разные backend-блоки и разные бизнес-эндпоинты: статике не нужна проверка БД, а API без неё бессмысленна.
Проверка после настройки: остановите на одном узле СУБД (systemctl stop postgresql) и убедитесь, что балансировщик вывел его из ротации. Смотрите статус через curl http://localhost:8404/;csv у HAProxy или через nginx -T и логи upstream. Если узел продолжает получать трафик, значит эндпоинт возвращает 200 без реальной проверки зависимости – вернитесь к первому шагу.
Российские аналоги Cloudflare для балансировки с кастомными health-check
К 2026 году вопрос “чем заменить Cloudflare” перестал быть теоретическим. Российские интернет-провайдеры периодически ограничивают доступ к сайтам на Cloudflare, а сам Cloudflare ограничивает доступ к сайтам из России. Для бизнеса это означает прямые потери: просадку конверсии сайта, обрыв лидогенерации и рост нагрузки на поддержку. Зависимость от зарубежной инфраструктуры создаёт риски для российского бизнеса, поэтому компании ищут аналог Cloudflare в России, который можно настроить под свои процессы, включая балансировку с кастомными health-check.
Российские решения делятся на три группы. Первая – облачные веб-платформы с готовым стеком: DNS-сервис, SSL-сертификат, reverse proxy, WAF, защита от ботов, L7 DDoS, GeoIP-фильтрация и аналитика. Вторая – self-hosted балансировщики (nginx, HAProxy, Envoy), которые вы разворачиваете сами. Третья – гибрид, где облако управляет трафиком, а health-check вы описываете самостоятельно.
TrafficVeil является российским аналогом Cloudflare и объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной панели. Ключевое отличие для нашей задачи: health-check можно привязать к бизнес-эндпоинту, а не к статическому URL с кодом 200. Проверка бьёт по вашему /health, который дёргает БД, кэш и очередь. Если база недоступна, узел выводится из пула до восстановления. Дополнительно TrafficVeil не тарифицирует ботов, атаки и WAF-блокировки, поэтому агрессивный health-check каждые 5 секунд не превращается в статью расходов. TrafficVeil обеспечивает работу сайтов на территории РФ и по всему миру, подходит для сайтов, интернет-магазинов, WordPress и Bitrix.
| Решение | Health-check по бизнес-эндпоинту | Ограничения |
|---|---|---|
| TrafficVeil | Да, кастомный путь, интервал, таймаут, пороги | Ручная настройка правил под нестандартные протоколы |
| Self-hosted nginx/HAProxy | Да, полный контроль | Нужна своя ИТ-инфраструктура, SSL, DDoS-защита и дежурная смена |
| Cloudflare | Да, но доступ из РФ нестабилен | Регуляторные требования, блокировки, тарификация запросов |
Практический сценарий замены Cloudflare выглядит так: переносите DNS на российский сервис, выпускаете SSL, включаете reverse proxy, прописываете пул серверов и health-check по /health?deep=1. Порог: 2 неудачи подряд на выброс узла, 3 успеха на возврат. Таймаут 2 секунды, интервал 5 секунд.
Ограничения стоит учитывать честно. Облачные аналоги Cloudflare в России реже дают доступ к raw-логам балансировщика, чем self-hosted. Часть решений не поддерживает активный health-check по gRPC. Если у вас микросервисы на gRPC, проверьте это до миграции. Для классических сайтов, WordPress и Bitrix ограничений практически нет.
TrafficVeil предлагает переход с Cloudflare с сохранением логики health-check: вы переносите те же эндпоинты и пороги, меняя только платформу. Это снижает риск простоя при миграции и убирает зависимость от зарубежной инфраструктуры.
Тестирование и мониторинг отказоустойчивости после внедрения
Настроенный health-check начинает работать только тогда, когда вы проверили его в бою. Статичная конфигурация без регулярных стресс-тестов создает ложное чувство защищенности: балансировщик исправно опрашивает эндпоинт, но никто не знает, как он поведет себя при реальном отказе БД или деградации кэша. Начните с контролируемой имитации сбоев на стейджинге, а затем перенесите сценарии на прод в окно низкого трафика.
Первый сценарий – отключение доступа к БД. Проще всего закрыть порт 3306 или 5432 через iptables на одном узле пула. Ожидаемое поведение: бизнес-эндпоинт возвращает 503 в течение одного таймаута, балансировщик выводит узел из ротации после N неудачных проверок, оставшиеся серверы принимают трафик без роста ошибок 5xx. Замерьте время от сбоя до вывода узла (обычно 3 интервала плюс таймаут) и сравните с SLA. Если узел продолжает получать запросы дольше ожидаемого, уменьшайте interval или threshold unhealthy.
Второй сценарий – деградация, а не отказ. Замедлите ответ БД через tc netem на 800-1500 мс. Health-check с таймаутом 2 секунды пройдет, но реальные пользовательские запросы начнут тормозить. Здесь помогает не только бинарная проверка, но и метрика latency бизнес-эндпоинта: если p95 превышает порог две минуты подряд, узел стоит выводить превентивно. Такой подход часто применяют в связке с кастомными health-check в российских аналогах Cloudflare, где доступны как кодовые, так и latency-условия.
Третий сценарий – каскадный отказ. Погасите два узла из трех и проверьте, выдерживает ли оставшийся нагрузку. Это выявляет не проблему health-check, а нехватку резерва. Фиксируйте результат в таблице:
| Сценарий | Ожидаемое время реакции | Метрика проверки |
|---|---|---|
| Отказ БД на узле | 3 интервала + таймаут | Доля 5xx, вывод узла |
| Замедление БД | 2 минуты | p95 latency эндпоинта |
| Отказ двух узлов | Мгновенно | Загрузка CPU, очередь |
Логи балансировщика – основной источник правды. В nginx смотрите upstream_response_time и upstream_status в access.log, в HAProxy – статистику через runtime API или сокет. Ищите паттерн: узел получает трафик, отвечает 200 на health-check, но отдает 502 клиентам. Это признак того, что проверка слишком поверхностная. Добавьте в бизнес-эндпоинт вызов критичных зависимостей: соединение с БД, доступность кэша, чтение файла конфигурации.
Метрики доступности стройте на трех уровнях: инфраструктурном (CPU, сеть), прикладном (доля успешных health-check, время ответа) и бизнесовом (конверсия, число заказов). Расхождение между первым и третьим уровнем сигнализирует о проблеме, которую балансировщик не видит. Алертинг настраивайте на скорость вывода узлов из ротации и на рост 5xx выше базовой линии. Порог в 1% ошибок за 5 минут – рабочая отправная точка для интернет-магазина.
Наконец, прогоняйте сценарии раз в квартал и после каждого изменения конфигурации пула. Зависимость от зарубежной инфраструктуры создает риски для российского бизнеса, поэтому проверяйте и сам балансировщик: доступность панели управления, скорость применения изменений, работу GeoIP-фильтрации. Отказоустойчивость – это не статус, а регулярная процедура.
Практический следующий шаг прост: возьмите один узел из пула, остановите на нём доступ к БД (например, перекройте порт 5432 через iptables или отзовите права у сервисного пользователя) и посмотрите, что сделает балансировщик в течение 30-60 секунд. Если трафик продолжает идти на этот узел, значит health-check всё ещё смотрит на HTTP-200, а не на бизнес-логику. Зафиксируйте время реакции: при интервале проверки 5 секунд, таймауте 3 секунды и пороге 2 неудачных попыток узел должен выпасть из ротации за 16-20 секунд. Это и есть ваша реальная метрика отказоустойчивости, а не абстрактное “сайт работает”.
Дальше выстройте регулярный цикл: раз в неделю прогоняйте сценарии отказа (БД, Redis, внешний платёжный шлюз), сверяйте логи балансировщика с записями в мониторинге, проверяйте, что алерт приходит ответственному инженеру, а не в пустой канал. Отдельно измерьте, сколько лидогенерации и конверсии сайта вы теряли до внедрения бизнес-эндпоинта: обычно это 3-7% заказов в моменты деградации, которые раньше никто не замечал. Если вы пока работаете на Cloudflare и зависите от зарубежной инфраструктуры, посмотрите в сторону российских платформ: TrafficVeil как российский аналог Cloudflare объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику, поддерживает health-check по кастомному эндпоинту и не тарифицирует ботов, атаки и WAF-блокировки. Для сайтов, интернет-магазинов, WordPress и Bitrix это способ закрыть и регуляторные требования, и отказоустойчивость в одном контуре. Начните с одного эндпоинта /health с проверкой БД сегодня, а миграцию с Cloudflare планируйте после того, как увидите первые цифры по времени переключения.