Как научить HAProxy снижать на проблемный backend
В этой статье рассказали о том, как повысить отказоустойчивость Directum RX с помощью health-agent, который оценивает не только доступность backend-узла, но и его фактическое состояние: ресурсы, контейнеры и работу отдельных сервисов. На основе этих данных HAProxy может снижать вес деградировавшего узла, исключать критично недоступный или постепенно возвращать его в балансировку.
Два backend-узла Directum RX сами по себе еще не гарантируют отказоустойчивость. Один из них может продолжать отвечать на HTTP-запросы с кодом 200, одновременно испытывая нехватку памяти, перегрузку CPU или проблемы с отдельными сервисами. В этот момент обычная проверка доступности продолжает считать узел исправным и направлять на него пользовательский трафик. В статье расскажем, как реализовать health-agent, который помогает HAProxy учитывать не только доступность, но и фактическую степень деградации backend-узла.
Когда HTTP 200 уже недостаточно
При построении отказоустойчивого контура Directum RX недостаточно просто развернуть несколько экземпляров приложения и поставить перед ними балансировщик нагрузки. Нужно понимать, способен ли конкретный узел нормально обрабатывать запросы в конкретный момент времени.
Классический health-check отвечает на бинарный вопрос: сервис доступен или нет. Например, HAProxy отправляет HTTP-запрос на заданный URL и, получив ожидаемый код ответа, считает backend работоспособным. Если проверка не проходит, узел исключается из балансировки.
Но между состояниями «полностью исправен» и «полностью недоступен» есть промежуточная зона. Узел может продолжать отвечать HTTP 200 и при этом:
- находиться под высокой загрузкой CPU;
- испытывать нехватку оперативной памяти;
- активно использовать swap;
- иметь заканчивающееся место на диске или inode;
- потерять связь с PostgreSQL;
- частично потерять связь с RabbitMQ;
- иметь недоступный PreviewService, IntegrationService или LogService;
- содержать контейнер Directum RX в состоянии Restarting или Exited.
Обычная проверка доступности не различает такие состояния. Для нее backend либо работает, либо нет. Поэтому при частичной деградации балансировщик может продолжать отправлять на проблемный узел столько же запросов, сколько и на исправный.
Именно для этой задачи появился проект Self-Healing Directum RX.
Что было предложено
Текущая версия проекта — v0/MVP, реализованная в виде Bash health-agent. Ее задача не в том, чтобы самостоятельно перезапускать каждый проблемный компонент, а в том, чтобы дать HAProxy более точную информацию о состоянии backend-узла.
RX-health-agent работает непосредственно на backend-узлах, выполняет локальные и сетевые проверки, объединяет результаты и передает итоговое состояние HAProxy через механизм agent-check.
В результате балансировщик получает не только сигнал «сервер доступен или недоступен», но и рекомендацию по весу backend-а:
6 сервисов · 2 столбца
Листайте столбцы →Смахните влевоВсе 2 столбца
Такой подход позволяет не отключать backend полностью при каждой проблеме. Если узел еще способен обслуживать запросы, но давать ему полную нагрузку уже нежелательно, HAProxy снижает его вес и отдает предпочтение более здоровому серверу.
Что проверяет health-agent
В версии v0 реализованы проверки:
- проверка доступности ключевых HTTP endpoint Directum RX;
- проверка /client/api/health;
- проверка /client/health;
- проверка StorageService;
- проверка PreviewService;
- проверка IntegrationService;
- проверка LogService;
- проверка состояния контейнеров Directum RX;
- проверка доступности Docker daemon;
- проверка свободного места на файловой системе;
- проверка inode;
- проверка CPU и load average;
- проверка RAM;
- проверка swap;
Кроме того, агент:
- формирует причину деградации;
- рассчитывает итоговый вес узла;
- поддерживает мягкую деградацию без полного отключения backend-а;
- позволяет вручную перевести узел в maintenance;
- поддерживает режим drain;
- использует recovery window перед полноценным возвратом backend-а в балансировку.
При этом уже сейчас важно четко обозначить границу возможностей это версии.
Health-agent не является системой общего мониторинга и не заменяет HAProxy, Keepalived, Patroni, RabbitMQ или решение «Мониторинг Directum RX». Его задача — максимально быстро принять решение о пригодности конкретного RX backend-а для дальнейшей обработки пользовательского трафика.
Архитектура тестового стенда
Для разработки и тестирования проекта развернут отдельный стенд Directum RX 26.1 на РЕД ОС 8.
В составе стенда для первой версии агента используются следующие группы узлов.
4 сервиса · 3 столбца
Листайте столбцы →Смахните влевоВсе 3 столбца
Для кластера балансировки используются два HAProxy-узла и Keepalived. Пользовательский трафик поступает на виртуальный IP и далее распределяется между backend-узлами Directum RX.
Для взаимодействия HAProxy с health-agent используется TCP-порт 9505.
Кто за что отвечает
В текущей архитектуре важно не смешивать функции 3-х компонентов.
rx-health-agent
Агент работает в контексте backend-узла Directum RX и оценивает:
· состояние самого RX;
· состояние контейнерной среды;
· ресурсы операционной системы.
Результатом
становится агрегированное состояние узла, например 100%, 75% или 50%, down, maint или drain.
HAProxy
HAProxy выполняет две проверки:
· штатный HTTP health-check конкретного сервиса Directum RX;
·
получение
дополнительного состояния backend-а через agent-check.
Именно HAProxy принимает окончательное решение о доступности узла и его весе в балансировке.
Keepalived
Keepalived отвечает не за отдельный backend Directum RX, а за доступность самого слоя балансировки. Если первый HAProxy-узел перестает выполнять свою функцию, Keepalived должен переключить виртуальный IP на второй HAProxy.
Проверку состояния HAProxy и Keepalived не следует смешивать с проверками RX health-agent. Для балансировщиков планируется отдельный локальный механизм.
Как устроена версия v0
Health-agent
устанавливается непосредственно на backend-узлы Directum RX. В тестовом контуре
это dev-ddc-rx261a
и dev-ddc-rx261b.
Для взаимодействия с HAProxy
используется TCP-порт
9505.
Состав файлов
Основной сценарий агента располагается в:
Конфигурационный файл:
Текущее состояние агента сохраняется в:
Для административного управления backend-узлом дополнительно используются marker-файлы:
Режимы maintenance, drain и механизм recovery уже входят в возможности Bash-версии v0.
В конфигурации задаются проверяемые endpoint-ы Directum RX, допустимые HTTP-коды, таймауты, пороги ресурсов операционной системы и параметры инфраструктурных проверок.
Для Client API используется endpoint:
с ожидаемым HTTP-кодом 200.
Отдельные warning- и critical-пороги предусмотрены для диска, inode, CPU/load average, RAM и swap.
Основная логика v0 реализована на Bash. За один вызов агент выполняет проверки, определяет найденные проблемы и формирует итоговое решение для HAProxy. Затем результат передается через systemd socket activation на TCP-порту 9505.
Для подключения к HAProxy используются agent-check и отдельный период проверки agent-inter.
После изменения конфигурации HAProxy она проверяется командой:
После успешной проверки конфигурацию можно применить через:
Политика для сервисов Directum RX
Для разных компонентов используются разные реакции на отказ:
12 сервисов · 3 столбца
Листайте столбцы →Смахните влевоВсе 3 столбца
На выходе агент может сформировать несколько состояний.
7 сервисов · 2 столбца
Листайте столбцы →Смахните влевоВсе 2 столбца
Client API, Web Client и StorageService считаются критичными. Если проверка одного из них не проходит, backend исключается из балансировки.
PreviewService и IntegrationService переводят узел в состояние с весом 50%, а LogService — с весом 75%. Пользовательский трафик продолжает обслуживаться обоими серверами, но HAProxy отдает предпочтение полностью исправному backend-у.
Административные режимы
Для планового вывода узла используется режим maintenance:
После этого агент возвращает состояние maint, а HAProxy переводит
backend в MAINT.
После окончания работ marker-файл удаляется:
Для более мягкого вывода используется режим drain:
touch /var/lib/rx-health-agent/drain
В
этом случае агент возвращает drain,
а HAProxy не должен направлять на backend новые обычные запросы.
После окончания работ файл также удаляется:
В
v0 предусмотрен и recovery window. После состояния down агент не сразу
возвращает backend к полной нагрузке. Сначала узел проходит переходное
состояние восстановления, после чего возвращается к рабочему весу.
Это снижает риск ситуации, когда недавно восстановившийся сервер мгновенно получает весь доступный объем трафика.
Пример мягкого вывода с помощью drain
Пример мягкого вывода с помощью recovery window
Как проверять работу
На стенде проверяются три сценария: деградация из-за ресурсов, полный отказ критичного компонента и частичный отказ отдельного сервиса.
Сценарий 1: Высокая загрузка CPU
Приложение может продолжать отвечать HTTP 200, хотя сервер уже находится под высокой нагрузкой. Для теста на RX-узле создается CPU-нагрузка:
Агент контролирует load average и при превышении warning-порога уменьшает вес backend-а.
Ожидаемый результат:
При этом первый сервер не переводится в DOWN: он продолжает работать, но HAProxy начинает отдавать предпочтение второму backend-у.
HAProxy Stats во время CPU-теста
Сценарий 2: Остановка критичного контейнера
Второй сценарий — отказ компонента, без которого RX backend уже нельзя считать нормально работоспособным.
На одном из RX-узлов останавливаем нужный критичный контейнер:
Его состояние можно проверить командой:
Если
контейнер Web Client или другого критичного компонента переходит в Exited либо другое
проблемное состояние, соответствующий health-check перестает проходить. Backend
переводится в down,
а трафик продолжает обслуживаться вторым RX-узлом.
Ожидаемое состояние:
HAProxy Stats после остановки контейнера веб-сервера
После завершения теста контейнер запускается обратно:
После успешных проверок и прохождения recovery window backend возвращается в балансировку.
Сценарий 3: Отказ PreviewService
Не каждый отказ должен приводить к полному отключению узла. Для PreviewService используется endpoint:
Если проверка перестает проходить, backend не переводится в
down. Вместо
этого агент уменьшает его вес до 50%:
Оба сервера продолжают обслуживать трафик, но HAProxy отдает предпочтение полностью исправному backend-у.
Почему для v0 выбрали Bash
На первом этапе нужно было быстро проверить саму концепцию: можно ли использовать фактическое состояние RX-узла для динамического управления балансировкой.
Для этого Bash оказался достаточным. Необходимые данные уже доступны штатными средствами Linux:
·
HTTP-проверки
выполняются через curl;
·
состояние
файловой системы получают через df;
·
сведения
о памяти — через free;
·
load average — из /proc;
· состояние контейнеров — командами Docker.
Bash-агент
не требует тяжелого runtime и может быть размещен непосредственно на RX-узле.
Сценарий легко изменить, проверить через bash
-n, выполнить на сервере и сопоставить результат с состоянием
HAProxy.
Для MVP этого оказалось достаточно. При этом Bash-версия рассматривается именно как v0 и проверка работоспособности идеи, а не как финальная реализация. По мере усложнения логики становятся важными история состояний, сложные API, статистика за временное окно и дополнительные механизмы стабилизации.
Что планируется дальше
В следующих версиях планируется:
· развить более глубокую диагностику RabbitMQ и PostgreSQL;
· учитывать время ответа сервисов;
· анализировать HTTP-ошибки за временной интервал;
· хранить историю состояний;
· улучшить защиту от частого изменения веса;
· реализовать полноценную проверку очередей RabbitMQ и SQL-проверка PostgreSQL;
· рассчитывать p95/p99 времени ответа HTTP-сервисов.
Следующая версия должна сохранить основную идею v0 — быстро формировать понятное решение для HAProxy, — но использовать больше данных для определения фактической деградации.
Наши рекомендации
При построении отказоустойчивого контура не ограничивайтесь проверкой доступности приложения: заранее определите, какие компоненты являются критичными, какие проблемы допускают мягкую деградацию, а какие требуют полного исключения узла из балансировки. Начинайте с минимального набора проверок и понятной матрицы реакций, тестируйте каждое состояние на стенде и отделяйте health-check от общего мониторинга и автоматического восстановления. Такой подход позволяет сначала проверить саму логику маршрутизации трафика, а затем последовательно расширять self-healing без преждевременного усложнения архитектуры.



