Skip to content

HAProxy

HAProxy (High Availability Proxy) — это высокопроизводительный, отказоустойчивый прокси-сервер и балансировщик нагрузки, способный работать как с HTTP(S), так и с TCP-трафиком. Это делает его идеальным решением не только для веб-приложений, но и для баз данных, почтовых систем, брокеров сообщений и других сервисов.

HAProxy позволяет:

  • увеличить доступность (если один сервер «падает», трафик уходит на другие),
  • масштабировать нагрузку при росте числа пользователей,
  • гибко управлять маршрутизацией запросов.

Балансировщик нагрузки принимает входящий сетевой трафик от клиента и, основываясь на некоторых критериях этого трафика, отправляет эти сообщения на один из нескольких бэкенд-серверов

config

Конфигурационный файл обычно располагается по следующему пути: /etc/haproxy/haproxy.cfg и делится на секции:

  • global – общие параметры (логи, количество процессов и пр.).
  • defaults – настройки по умолчанию для всех фронтендов и бэкендов.
  • frontend – «лицо» балансировщика, куда приходит трафик от клиентов.

    Frontend определяет IP-адреса и порты, к которым могут подключаться клиенты, то есть, по сути, определяет внешний интерфейс подключения и состоит из следующих компонентов:

    • набор IP-адресов и порт (например, 172.16.35.12:80, *:443 и т.д);
    • ACL-правила use_backend, которые определяют, какие бэкенды использовать в зависимости от условий ACL;
    • правило default_backend, которое обрабатывает все остальные случаи.
  • backend – список серверов, на которые распределяется трафик.

    В базовом варианте бэкенд определяется следующим образом:

    • выбор алгоритма балансировки;
    • список серверов и портов.

    Бэкенд может содержать в себе один или несколько серверов. И в общем случае, это и является прямым назначением HAProxy — добавление большего количества серверов, для того чтобы увеличить потенциальную емкость нагрузки путем распределения ее на несколько серверов. Плюс таким же образом достигается повышение надежности на случай, если некоторые из внутренних серверов станут недоступными.

Простой пример HTTP-балансировки между двумя срверами:

/etc/haproxy/haproxy.cfg
global
    log /dev/log    local0
    log /dev/log    local1 notice
    daemon

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000

frontend http_front
    bind *:80
    default_backend http_back

backend http_back
    balance roundrobin
    server web1 192.168.1.10:80 check
    server web2 192.168.1.11:80 check
проверка конфига
haproxy -c -f /etc/haproxy/haproxy.cfg

Алгоритмы балансировки нагрузки

Используемый алгоритм балансировки нагрузки определяет, какой сервер в бэкенде будет выбран при балансировке нагрузки. HAProxy предлагает несколько вариантов алгоритмов, причем в дополнение к алгоритму распределения нагрузки серверам может быть назначен весовой параметр для управления частотой выбора сервера относительно других. HAProxy предоставляет достаточно tбольшое количество алгоритмовt, вот лиш некоторые из них:

  • roundrobin — алгоритм, который выбирает серверы по очереди, является алгоритмом по умолчанию..
  • leastconn – отправляет запросы на сервер с наименьшим числом активных соединений.
  • source – этот алгоритм выбирает, какой сервер использовать, основываясь на хеш-адресе исходного IP-адреса, то есть IP-адреса пользователя, это один из способов гарантировать, что пользователь будет подключаться к одному и тому же серверу.
  • uri/hdr/cookie – балансировка на основе URI, заголовков или cookies.

stats

HAProxy умеет показывать удобную веб-страницу с текущими метриками.

stats
listen stats
    bind *:8080
    stats enable
    stats uri /stats
    stats auth admin:strongpass

Страница статистики будет доступна по адресу: http://<haproxy-host>:8080/stats.

logging

Логи по умолчанию идут в rsyslog: /var/log/haproxy.log

health check

HAProxy использует проверку работоспособности, чтобы определить, доступен ли внутренний сервер для обработки запросов. Это позволяет избежать необходимости вручную удалять сервер из конфигурации, если он становится недоступным. Проверка работоспособности по умолчанию заключается в попытке установить TCP-соединение с сервером, т.е. происходит проверка, прослушивает ли внутренний сервер заданные IP-адрес и порт. Если сервер не проходит проверку работоспособности и, следовательно, не может обслуживать запросы, то он автоматически отключается в бэкенде, и трафик не будет перенаправляться на него, пока он снова не станет работоспособным. Если же все серверы в бэкенде выйдут из строя, то приложение или сервис станет недоступно, пока хотя бы один из этих бэкенд-серверов снова не станет работоспособным.

check
server web1 192.168.1.20:80 check inter 5s rise 2 fall 3

# inter 5s — проверка каждые 5 секунд.
# rise 2 — сервер считается «здоровым», если успешно ответил 2 раза подряд.
# fall 3 — считается «павшим» после 3 неудачных проверок.

routing

L4-routing

Layer 4 (TCP) — прозрачная проксификация на уровне транспортного протокола: полезно для баз данных, SMTP, любых TCP-служб.

L4-routing - это просто и быстро, работает на транспортном уровне, внутрь пакета не смотрит, поэтому экономичный по ресурсам. Кофигурируется тоже просто: во frontend указывается порт, который нужно слушать; в backend список серверов, куда пересылается трафик.

layer 4 routing
frontend postgresql
  mode tcp
  bind :5432
  default_backend postgresql_servers

backend postgresql_servers
  mode tcp
  balance leastconn
  server sql1 192.168.0.10:3306
  server sql2 192.168.0.11:3306

Такой режим практически не нагружает процессор, позволяет обрабатывать десятки тысяч соединений и подходит для сервисов, где не требуется анализ содержимого запросов.

L7-routing

  • Layer 7 (HTTP) — работа с HTTP-заголовками, возможность роутинга по URI, доменам, cookies.

L7-routing - это умная и дорогая маршрутизация, каждый пакет анализируется на основе ACL-правил и перенаправляется на соответствующий сервер.

layer 7 routing
frontend http_front
    bind *:80

    # ACL №1 — путь /api
    acl is_api path_beg /api

    # ACL №2 — путь /admin
    acl is_admin path_beg /admin

    # ACL №3 — отдача статики
    acl is_static path_end .css .js .png .jpg

    # Маршрутизация
    use_backend api_servers    if is_api
    use_backend admin_servers  if is_admin
    use_backend static_servers if is_static

    # Backend по умолчанию
    default_backend default_servers


backend api_servers
    balance roundrobin
    server api1 10.0.0.11:8080 check
    server api2 10.0.0.12:8080 check


backend admin_servers
    balance roundrobin
    server admin1 10.0.0.21:8080 check


backend static_servers
    balance roundrobin
    server static1 10.0.0.31:80 check
    server static2 10.0.0.32:80 check


backend default_servers
    balance roundrobin
    server web1 10.0.0.41:80 check

Такой подход требует больше CPU и памяти из-за разбора протокола, но даёт максимальную гибкость в управлении трафиком и позволяет реализовывать сложные схемы маршрутизации.

ACL

ACL (Access Control List) — это универсальный инструмент, позволяющий описывать условия обработки запросов на основе различных признаков: IP-адреса клиента, пути и параметров URL, HTTP-заголовков, методов, доменов SNI, а также регулярных выражений и масок. По сути, ACL — это условие if в конфигурации HAProxy: оно вычисляется для каждого запроса, и в зависимости от результата (true/false) выбирается нужное действие — перенаправить, заблокировать, модифицировать или отправить в определённый backend. Благодаря ACL конфигурация перестаёт быть статичной и превращается в набор динамических правил, реагирующих на контекст запроса. Это особенно важно для маршрутизации (routing), когда от характеристик запроса зависит выбор целевого сервиса.

Порядок ACL имеет значение - правила проверяются сверху вниз

Sticky sessions

Привязка клиента к серверу, если веб-приложению нужна «сессия» на одном бэкенде (например, хранение корзины в памяти), добавляют cookie:

cookie
backend http_back
    balance roundrobin
    cookie SERVERID insert indirect nocache
    server web1 192.168.1.10:80 check cookie s1
    server web2 192.168.1.11:80 check cookie s2

timeouts

В конфигурации HAProxy директивы timeout используются для определения различных предельных временных интервалов, влияющих на установление соединений, передачу запросов и откликов, а также поведение keep-alive-соединений. Все таймауты задаются в секундах, миллисекундах или комбинированном формате (10s, 500ms, 1m), и их можно указывать как в секции defaults, так и в секциях frontend или backend — приоритет отдается более локальной настройке. Таймауты — очень важные настройки. Они помогают избежать долгих висящих TCP-соединений, которые могут занимать дескрипторы, и позволяют использовать эти ресурсы для других соединений.

  • timeout connect. Время на установку TCP-соединения с backend-сервером. Если backend не отвечает → сервер считается недоступным. timeout connect 5s
  • timeout client. Максимальное время бездействия клиента. timeout client 30s
  • timeout server. Максимальное время бездействия backend-сервера. Если backend не отвечает или завис, соединение завершится по истечении заданного времени. timeout server 30s
  • timeout http-request. Время ожидания полного HTTP запроса (headers). timeout http-request 10s
  • timeout http-keep-alive. Idle время между HTTP запросами на одном соединении. timeout http-keep-alive 10s
  • timeout queue. Сколько запрос может ждать свободный backend. Если backend перегружен → запрос падает. timeout queue 30s
  • timeout retry. Пауза между попытками соединения. timeout retry 3s
  • timeout tunnel. Очень важный для: WebSocket, gRPC, SSH proxy, VPN, long connections. Если не указать → соединения будут рваться. timeout tunnel 1h
  • timeout tarpit — время ожидания при использовании механизма tarpitting (например, при блокировке клиентов). Это может применяться для создания искусственной задержки на подозрительных запросах. timeout tarpit 10s
  • timeout check. Таймаут health-check проверки backend-сервера. timeout check 5s

```cfg title="Пример production defaults defaults timeout connect 500ms timeout client 30s timeout server 30s timeout http-request 3s timeout http-keep-alive 10s timeout queue 10s timeout tarpit 10s timeout tunnel 30m timeout client-fin 10s timeout server-fin 10s timeout check 3s

Text Only
> HAProxy НЕ любит отсутствующие таймауты. Если не указать → warning: `missing timeouts for backend`. И могут появиться висящие соединения.

```text title="Как посмотреть причины таймаута"
Логи HAProxy содержат termination flags:
sC  → server timeout
cC  → client timeout
SC  → server connection error
PR  → proxy reject


Очень полезная статья про HAProxy