Как научить HAProxy снижать на проблемный backend

В этой статье рассказали о том, как повысить отказоустойчивость Directum RX с помощью health-agent, который оценивает не только доступность backend-узла, но и его фактическое состояние: ресурсы, контейнеры и работу отдельных сервисов. На основе этих данных HAProxy может снижать вес деградировавшего узла, исключать критично недоступный или постепенно возвращать его в балансировку.

Обложка: Как научить HAProxy снижать на проблемный backend

Два 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 столбца
СостояниеРеакция
Нормаbackend работает с весом 100%
Мягкая деградациявес backend-а уменьшается до 75% или 50%
Критический отказbackend переводится в down и исключается из балансировки
Плановое обслуживаниеиспользуется maint
Мягкий административный выводиспользуется drain
Восстановлениеузел проходит recovery window и возвращается к рабочему весу
Листайте столбцы →Смахните влевоВсе 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.

Как научить HAProxy снижать на проблемный backend_23

В составе стенда для первой версии агента используются следующие группы узлов.

4 сервиса · 3 столбца
УзелНазначениеМинимальные ресурсы
dev-ddc-hap-01HAProxy + Keepalived, node 12 vCPU, 4 ГБ RAM
dev-ddc-hap-02HAProxy + Keepalived, node 22 vCPU, 4 ГБ RAM
dev-ddc-rx261aDirectum RX 26.1 backend 16 vCPU, 16 ГБ RAM
dev-ddc-rx261bDirectum RX 26.1 backend 26 vCPU, 16 ГБ RAM
Листайте столбцы →Смахните влевоВсе 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.

Состав файлов

Основной сценарий агента располагается в:

			/opt/rx-health-agent/rx-health-agent.sh
		

Конфигурационный файл:

			/etc/rx-health-agent/rx-health-agent.conf
		

Текущее состояние агента сохраняется в:

			/var/lib/rx-health-agent/state.json
		

Для административного управления backend-узлом дополнительно используются marker-файлы:

			/var/lib/rx-health-agent/maintenance
/var/lib/rx-health-agent/drain

		

Режимы maintenance, drain и механизм recovery уже входят в возможности Bash-версии v0.

Как научить HAProxy снижать на проблемный backend_56

В конфигурации задаются проверяемые endpoint-ы Directum RX, допустимые HTTP-коды, таймауты, пороги ресурсов операционной системы и параметры инфраструктурных проверок.

Для Client API используется endpoint:

			/client/api/health
		

с ожидаемым HTTP-кодом 200.

Отдельные warning- и critical-пороги предусмотрены для диска, inode, CPU/load average, RAM и swap.

Основная логика v0 реализована на Bash. За один вызов агент выполняет проверки, определяет найденные проблемы и формирует итоговое решение для HAProxy. Затем результат передается через systemd socket activation на TCP-порту 9505.

Для подключения к HAProxy используются agent-check и отдельный период проверки agent-inter.

После изменения конфигурации HAProxy она проверяется командой:

			sudo haproxy -c -f /etc/haproxy/haproxy.cfg
		

После успешной проверки конфигурацию можно применить через:

			sudo systemctl reload haproxy
		

Политика для сервисов Directum RX

Для разных компонентов используются разные реакции на отказ:

12 сервисов · 3 столбца
ПроверкаЧто контролируетсяРеакция
Client API/client/api/healthdown
Web Client/client/healthdown
StorageService/storage/healthdown
PreviewService/preview/health50%
IntegrationService/integration/health50%
LogService/log/health75%
Dockerdaemon и состояние контейнеров50% / down
CPU / Loadнагрузка операционной системы50% / down
RAMиспользование памяти50% / down
Swapиспользование swap50%
Diskзаполнение файловой системы50% / down
Inodeдоступные inode50% / down
Листайте столбцы →Смахните влевоВсе 3 столбца

На выходе агент может сформировать несколько состояний.

7 сервисов · 2 столбца
РезультатЗначение
100%узел полностью работоспособен
75%небольшая деградация
50%существенная деградация
downузел необходимо исключить
maintплановое обслуживание
drainмягкий административный вывод
up / readyпереходное состояние восстановления
Листайте столбцы →Смахните влевоВсе 2 столбца

Client API, Web Client и StorageService считаются критичными. Если проверка одного из них не проходит, backend исключается из балансировки.

PreviewService и IntegrationService переводят узел в состояние с весом 50%, а LogService — с весом 75%. Пользовательский трафик продолжает обслуживаться обоими серверами, но HAProxy отдает предпочтение полностью исправному backend-у.

Административные режимы

Для планового вывода узла используется режим maintenance:

			touch /var/lib/rx-health-agent/maintenance
		

После этого агент возвращает состояние maint, а HAProxy переводит backend в MAINT.

После окончания работ marker-файл удаляется:

			rm -f /var/lib/rx-health-agent/maintenance
		

Для более мягкого вывода используется режим drain:

touch /var/lib/rx-health-agent/drain

В этом случае агент возвращает drain, а HAProxy не должен направлять на backend новые обычные запросы.

После окончания работ файл также удаляется:

			rm -f /var/lib/rx-health-agent/drain
		

В v0 предусмотрен и recovery window. После состояния down агент не сразу возвращает backend к полной нагрузке. Сначала узел проходит переходное состояние восстановления, после чего возвращается к рабочему весу.

Это снижает риск ситуации, когда недавно восстановившийся сервер мгновенно получает весь доступный объем трафика.

Как научить HAProxy снижать на проблемный backend_88

Пример мягкого вывода с помощью drain

Как научить HAProxy снижать на проблемный backend_90

Пример мягкого вывода с помощью recovery window

Как проверять работу

На стенде проверяются три сценария: деградация из-за ресурсов, полный отказ критичного компонента и частичный отказ отдельного сервиса.

Сценарий 1: Высокая загрузка CPU

Приложение может продолжать отвечать HTTP 200, хотя сервер уже находится под высокой нагрузкой. Для теста на RX-узле создается CPU-нагрузка:

			stress-ng --cpu
<количество_потоков>
		

Агент контролирует load average и при превышении warning-порога уменьшает вес backend-а.

Ожидаемый результат:

			dev-ddc-rx261a = 50%
dev-ddc-rx261b = 100%


		

При этом первый сервер не переводится в DOWN: он продолжает работать, но HAProxy начинает отдавать предпочтение второму backend-у.

Как научить HAProxy снижать на проблемный backend_101

HAProxy Stats во время CPU-теста

Сценарий 2: Остановка критичного контейнера

Второй сценарий — отказ компонента, без которого RX backend уже нельзя считать нормально работоспособным.

На одном из RX-узлов останавливаем нужный критичный контейнер:

			docker stop <container>
		

Его состояние можно проверить командой:

			docker ps -a
		

Если контейнер Web Client или другого критичного компонента переходит в Exited либо другое проблемное состояние, соответствующий health-check перестает проходить. Backend переводится в down, а трафик продолжает обслуживаться вторым RX-узлом.

Ожидаемое состояние:

			dev-ddc-rx261a = DOWN
dev-ddc-rx261b = UP
		
Как научить HAProxy снижать на проблемный backend_112

HAProxy Stats после остановки контейнера веб-сервера

После завершения теста контейнер запускается обратно:

			docker start <container>
		

После успешных проверок и прохождения recovery window backend возвращается в балансировку.

Сценарий 3: Отказ PreviewService

Не каждый отказ должен приводить к полному отключению узла. Для PreviewService используется endpoint:

			/preview/health
		

Если проверка перестает проходить, backend не переводится в down. Вместо этого агент уменьшает его вес до 50%:

			dev-ddc-rx261a = UP, 50%
dev-ddc-rx261b = UP, 100%

		

Оба сервера продолжают обслуживать трафик, но 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 без преждевременного усложнения архитектуры.

Рекомендуем