HAProxy + Keepalived: отказоустойчивый балансировщик нагрузки для корпоративных сервисов
Привет! Меня зовут Евгений Сергеевич Семёнов, и я директор ITFresh. Если спросите меня про любимый инструмент для балансировки нагрузки, то это, бесспорно, HAProxy! Он удивительно лёгок, буквально летает, а документация к нему — просто песня. При этом HAProxy спокойно выдерживает десятки тысяч соединений даже на совсем скромном оборудовании. Но есть одна загвоздка, которая не даёт мне покоя: сам HAProxy, как ни крути, может стать той самой единственной точкой отказа. Представьте: если он вдруг «упадёт», всё, что за ним, тоже перестанет работать. Именно поэтому в боевом окружении я ни за что не рискну поставить один-единственный HAProxy. Всегда, слышите, всегда использую его только в паре с Keepalived. И вот тут-то я и покажу вам весь наш процесс: от установки до того, как система молниеносно переключится всего за 3 секунды, если активный узел вдруг решит взять отпуск.
Задача и архитектура
Представьте себе такую ситуацию: у нас есть три веб-сервера, на каждом из которых работают Nginx и 1С веб-клиент. В пиковые часы трафик взлетает до 500 запросов в секунду. Нам нужен один, единственный HTTPS-адрес для входа — пусть будет 10.10.10.100. Что здесь самое критичное? Во-первых, если вдруг один из веб-серверов «ляжет», весь трафик обязан моментально переключиться на живые. Во-вторых, а если «упадёт» сам балансировщик? Его дублёр должен подхватить виртуальный IP в считанные секунды. И, пожалуй, самое главное условие: никаких, абсолютно никаких разрывов пользовательских сессий!
Архитектура:
- VIP 10.10.10.100 — плавающий адрес, который видит DNS и клиенты.
- lb01 10.10.10.101 — MASTER, HAProxy + Keepalived, приоритет 150.
- lb02 10.10.10.102 — BACKUP, HAProxy + Keepalived, приоритет 100.
- web01/02/03 10.10.10.201-203 — бэкенды Nginx + 1С.
- VRRP instance 51, интерфейс eth0, authentication PASS.
Для балансировщиков мы обычно выбираем довольно скромные виртуальные машины. Например, мне вполне хватает 2 vCPU, 2 ГБ оперативной памяти и 20 ГБ диска. И, конечно же, старый добрый Debian 12. По нашему опыту, HAProxy на таком железе легко справляется с нагрузкой в 20-30 тысяч запросов в секунду. Просто без каких-либо видимых проблем!
Установка HAProxy и Keepalived
Что ж, приступим к делу: на обеих наших виртуалках первым делом устанавливаем необходимые пакеты. Берём их, конечно, прямо из официального репозитория Debian. Я всегда стараюсь использовать HAProxy 2.8 LTS, забирая его из backports. Почему именно эта версия? Да просто потому, что она, на мой взгляд, предлагает лучшую поддержку HTTP/2 и TLS 1.3.
# На lb01 и lb02
sudo apt update
sudo apt install -y haproxy keepalived
# Включаем forwarding и non-local bind (нужно для VIP)
cat << EOF | sudo tee /etc/sysctl.d/99-haproxy.conf
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
Параметр ip_nonlocal_bind позволяет HAProxy слушать VIP даже на пассивной ноде — иначе бэкап-нода при поднятии адреса не сможет принять соединения.
Конфиг HAProxy
Конфигурация у нас абсолютно идентичная на обеих нодах. Чтобы избежать расхождений, мы всегда синхронизируем её через rsync. Обычно это происходит прямо из нашего git-репозитория в процессе деплоя — так надёжнее.
# /etc/haproxy/haproxy.cfg
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
maxconn 20000
ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5s
timeout client 30s
timeout server 30s
retries 3
frontend web_https
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/portal.corp.ru.pem alpn h2,http/1.1
http-request redirect scheme https unless { ssl_fc }
http-request set-header X-Forwarded-Proto https
default_backend web_pool
backend web_pool
balance leastconn
cookie SRVID insert indirect nocache
option httpchk GET /health HTTP/1.1\r\nHost:\ portal.corp.ru
http-check expect status 200
server web01 10.10.10.201:443 check ssl verify none cookie w1
server web02 10.10.10.202:443 check ssl verify none cookie w2
server web03 10.10.10.203:443 check ssl verify none cookie w3
listen stats
bind 127.0.0.1:9000
stats enable
stats uri /
stats refresh 5s
stats admin if TRUE
Есть несколько ключевых настроек, на которые стоит обратить внимание: * `balance leastconn`: эта директива заставляет HAProxy выбирать бэкенд с наименьшим числом активных соединений. При обработке «тяжёлых» или долгих запросов это куда эффективнее классического `round-robin`. * `Cookie SRVID`: обеспечивает так называемые «sticky sessions». Благодаря этой настройке клиент всегда привязывается к одному и тому же бэкенду через специальную cookie. * `Option httpchk` с `HTTP 1.1`: позволяет нам проверять, живы ли наши бэкенды. Проверка происходит каждые две секунды — так мы уверены, что трафик всегда идёт на рабочие серверы.
Конфиг Keepalived на MASTER
Так что же такое Keepalived? Если говорить просто, это VRRP-демон, его задача — следить за тем, чтобы виртуальный IP (VIP) всегда был назначен кому-то из узлов. Интересно, что конфигурация на наших `lb01` и `lb02` практически идентична. Главное отличие — их роли и, конечно, приоритеты.
# /etc/keepalived/keepalived.conf на lb01 (MASTER)
global_defs {
router_id LB01
script_user root
enable_script_security
}
vrrp_script chk_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight 2
fall 2
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass ДлинныйПароль17Знаков!
}
virtual_ipaddress {
10.10.10.100/24 dev eth0
}
track_script {
chk_haproxy
}
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}
Конфиг Keepalived на BACKUP
# /etc/keepalived/keepalived.conf на lb02 (BACKUP)
global_defs {
router_id LB02
script_user root
enable_script_security
}
vrrp_script chk_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight 2
fall 2
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass ДлинныйПароль17Знаков!
}
virtual_ipaddress {
10.10.10.100/24 dev eth0
}
track_script {
chk_haproxy
}
}
Основные отличия кроются в двух строчках: на резервном сервере мы указываем `state BACKUP` вместо `MASTER`, а приоритет снижаем до `priority 100` вместо `150`. Вот и всё! Заметьте, всё остальное остаётся идентичным. И это критично, особенно для `virtual_router_id` и `auth_pass` — без них ноды просто не смогут «увидеть» друг друга и начать корректно взаимодействовать.
Скрипт уведомления о переключении
Знаете, когда система переключается между MASTER и BACKUP, я моментально получаю алерт в Telegram. Для меня это не просто уведомление, а очень критичное событие. О таком нужно знать в реальном времени, без каких-либо промедлений, чтобы держать руку на пульсе!
#!/bin/bash
# /etc/keepalived/notify.sh
TYPE=$1
BOT_TOKEN="1234567890:AAA..."
CHAT_ID="-1001234567890"
HOST=$(hostname)
TIME=$(date '+%Y-%m-%d %H:%M:%S')
curl -sSf -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d "chat_id=$CHAT_ID" \
-d "text=HAProxy VRRP transition: $HOST → $TYPE at $TIME"
logger -t keepalived-notify "Transition to $TYPE"
sudo chmod +x /etc/keepalived/notify.sh
sudo systemctl enable --now keepalived haproxy
ip addr show eth0 | grep 10.10.10.100
Таблица: рекомендации по параметрам
| Параметр | Значение | Обоснование |
|---|---|---|
| advert_int | 1 сек | Быстрое обнаружение падения, 3 секунды до переключения |
| priority (MASTER) | 150 | Запас 50 пунктов над BACKUP для track_script weight |
| track_script weight | +2 (positive) | Если HAProxy жив — даёт бонус к приоритету |
| fall/rise | 2/2 | Не ведёт к флапам от разовых затыков |
| virtual_router_id | 1-255 | Уникальный в пределах L2-домена, иначе конфликт с другим кластером |
Проверка отказоустойчивости
После того, как всё запущено, мы обязательно проводим целенаправленное тестирование. И, конечно, делаем это не на production. Лично я всегда прогоняю три основных сценария проверки:
- Падение HAProxy на MASTER:
sudo systemctl stop haproxyна lb01 → через 4 секунды VIP переезжает на lb02, алерт в Telegram. - Перезагрузка MASTER:
sudo rebootна lb01 → VIP переезжает, через 2 минуты lb01 возвращается и забирает VIP обратно (если preemption on). - Падение бэкенда: останавливаем nginx на web02 → HAProxy выводит из пула, трафик идёт на web01/web03 без потерь.
Кейс: HA-балансировщик для медицинской сети
В мае 2026 года к нам обратился клиент — крупная сеть из девяти клиник по Москве и области. У них был единый портал для записи на приём. Проблема в том, что до нас всю нагрузку держал один HAProxy, запущенный на обычной виртуалке. И как вы думаете? Раз в пару месяцев он стабильно «падал» примерно на час, причины были самые разные. Что это означало для бизнеса? Запись в клиники попросту вставала, а пациенты, естественно, не могли попасть к врачу и начинали жаловаться.
Мы быстро развернули пару `lb01`/`lb02` на виртуалках прямо в дата-центре МТС. Настроили Keepalived, присвоив ему виртуальный IP 10.50.0.100. За этим балансировщиком расположились шесть бэкендов, на каждом из которых трудились Nginx и PHP-приложение. Конечно же, мы позаботились о сертификате `portal.clinic.ru`, включили HTTP/2, активировали сжатие `gzip` и настроили кэширование статики прямо на балансировщике. Что же показали первые два месяца работы?
- Самое главное — портал оставался доступным на протяжении всего этого времени! Ни одного, подчёркиваю, ни одного эпизода недоступности. При этом основной балансировщик, `lb01`, успел дважды перезагрузиться для обновления ядра. Система сработала идеально!
- Мы добились потрясающих результатов: время ответа сайта упало с 450 мс до всего 180 мс! Это почти в 2.5 раза быстрее. Как нам это удалось? Просто грамотно настроили HTTP/2 и активировали технологию keepalive.
- Нам важно, чтобы наши системы работали бесперебойно. Поэтому мы тщательно мониторим нагрузку. Например, на 40G Mellanox-оборудовании, которое находится прямо в дата-центре МТС, она никогда не превышает 8%. Представляете, это означает, что у нас есть 12-кратный запас по мощности!
- Наш клиент изначально рассматривал миграцию на облачный балансировщик. Но после детального анализа мы вместе пришли к выводу: зачем платить больше? Мы показали, что в текущей ситуации нет никакого экономического смысла в таком переходе. В итоге, от этой идеи отказались, сохранив бюджет.
Весь проект обошёлся в 110 000 рублей, и мы уложились всего в три рабочих дня. Это без учёта стоимости самого железа, конечно.
Типичные ошибки
- Один virtual_router_id на несколько кластеров — VIP будет пинг-понгиться между разными парами. У нас на практике это ломало AD в одной компании, пока не нашли.
- Нет track_script — HAProxy упал, но Keepalived этого не знает, VIP остался на мёртвой ноде.
- Strict ARP не настроен — если используете Linux бэкенды с VIP, включайте arp_ignore=1, arp_announce=2.
- Multicast заблокирован на коммутаторе — VRRP работает через 224.0.0.18, если multicast отфильтрован, ноды не видят друг друга, обе становятся MASTER.
- Не синхронизировали конфиги — поправили HAProxy на lb01, забыли на lb02, после переключения всё сломалось. Я всегда кладу конфиги в git и деплою через Ansible.
Развернём отказоустойчивый балансировщик под ключ
Настраиваем HAProxy + Keepalived для корпоративных веб-сервисов, 1С веб-клиента, SQL-прокси, почтовых серверов. Пара виртуалок, VIP, health-checks, SSL termination, алерты — за 2-3 рабочих дня.
Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш
FAQ — частые вопросы по HAProxy и Keepalived
- Зачем нужен Keepalived поверх HAProxy?
- HAProxy балансирует трафик между бэкендами, но сам становится точкой отказа. Keepalived через VRRP присваивает виртуальный IP активному узлу и автоматически переключает его на резервный при падении.
- Что такое VRRP?
- Virtual Router Redundancy Protocol — протокол выбора мастера в группе роутеров. Один узел держит виртуальный IP, остальные следят за ним через multicast. Если мастер пропал — выбирается новый по приоритету.
- Active-active или active-passive?
- Active-passive проще в настройке и диагностике: один узел работает, второй ждёт. Active-active с двумя VIP и round-robin DNS даёт вдвое больше ёмкости, но сложнее в отладке и требует синхронизации сессий.
- Нужен ли выделенный vlan для VRRP?
- Не обязательно, но желательно. На одном vlan с боевым трафиком VRRP-пакеты могут потеряться при шторме. Я выношу управляющий трафик на отдельный интерфейс или vlan.
- Как проверить, что VIP переключился?
- На активном узле ip addr show покажет виртуальный IP на интерфейсе. На пассивном — его не будет. journalctl -u keepalived пишет все транзиции MASTER/BACKUP.
