Перейти к основному содержимому

Балансировка нагрузки

Разработчику Архитектору Инженеру

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


Балансировка нагрузки

Что такое балансировка нагрузки?

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

Балансировщик нагрузки — это программное или аппаратное решение, которое управляет потоком входящих запросов и направляет их на доступные серверы или узлы. Он также может выполнять дополнительные функции, такие как мониторинг состояния серверов, проверка работоспособности (health checks) и автоматическое исключение неисправных узлов из пула.

image-2.png

Балансировка работает так:

  • клиент отправляет запрос на IP-адрес или доменное имя, которое указывает на балансировщик нагрузки;
  • балансировщик принимает запрос и решает, на какой сервер его направить;
  • балансировщик использует алгоритм распределения для выбора подходящего сервера;
  • перед отправкой запроса балансировщик может проверить состояние сервера;
  • запрос передаётся выбранному серверу, который обрабатывает его и возвращает ответ клиенту;
  • балансировщик постоянно отслеживает производительность серверов и их доступность - если один из них выходит из строя, балансировщик автоматически перестаёт направлять на него запросы.

Play ITЗагрузка интерактивного демо…

Play ITЗагрузка интерактивного демо…


Виды балансировщиков нагрузки

Балансировщики могут быть программными, аппаратными и облачными.

Аппаратные балансировщики представляют собой специализированное оборудование, разработанное для высокопроизводительной балансировки, к примеру, F5 BIG-IP, Citrix ADC.

Облачные балансировщики же предоставляются облачными провайдерами как сервис. Как мы уже рассматривали в облачных технологиях, их предоставляют техногиганты, соответственно, это AWS Elastic Load Balancer (ELB), Google Cloud Load Balancer, Azure Load Balancer.

Программные балансировщики реализованы как часть программного обеспечения, к примеру, NGINX, HAProxy, Apache HTTP Server, Traefik. Среди функций таких балансировщиков может быть не только распределение запросов между серверами для предотвращения перегрузки, но и мониторинг состояния и шифрование HTTPS-трафика.

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

NGINX — веб-сервер, с функционалом балансировщика нагрузки. Он работает на уровне приложений (L7) и поддерживает различные алгоритмы балансировки.

Apache HTTP Server предоставляет модуль mod_proxy_balancer, который позволяет использовать его как балансировщик нагрузки. Это решение подходит для небольших проектов или сред, где уже используется Apache в качестве веб-сервера.

Traefik — балансировщик нагрузки, ориентированный на работу в облачных средах и микросервисной архитектуре. Он автоматически обнаруживает сервисы через интеграцию с Docker, Kubernetes, Consul и другими оркестраторами. Может быть избыточным для простых проектов.

AWS Elastic Load Balancer — это облачное решение от Amazon Web Services. Оно предлагает три типа балансировщиков: Application Load Balancer (L7), Network Load Balancer (L4) и Classic Load Balancer (универсальный). ELB автоматически масштабируется и интегрируется с другими сервисами AWS.

ТипУровень OSIЧто видитПример
L4 (TCP/UDP)ТранспортIP, порт, соединениеNLB, HAProxy mode tcp
L7 (HTTP)ПриложениеURL, заголовки, cookiesNGINX, ALB, Traefik

L7 удобен для маршрутизации /api на один пул, /static на другой и для TLS-терминации. L4 даёт меньшую задержку и подходит для gRPC/TCP, когда не нужно разбирать HTTP-заголовки. Подробнее про HTTP — основа веб-интеграций.

Health check — обязательная часть конфигурации: балансировщик периодически вызывает GET /health (или TCP-connect) и исключает узлы с ошибками из пула, иначе трафик продолжит идти на "мёртвый" инстанс после деплоя.


Настройка и конфигурация балансировщика

Как настроить балансировщик нагрузки?

Рассмотрим на примере HAProxy.

Так, у нас есть приложение, запущенное в нескольких контейнерах, и оркестратор (к примеру, Docker Compose). Важный момент - мы изучим контейнеризацию и работу Docker отдельно, поэтому к этому алгоритму вы сможете вернуться позже.


Установить HAProxy

Установить HAProxy через пакетный менеджер или запустить его в отдельном контейнере через Docker:

docker pull haproxy:latest

Разбор:

  • docker pull haproxy:latest скачивает образ балансировщика; дальше в контейнер монтируют haproxy.cfg с frontend/backend.

Конфигурация

HAProxy работает по конфигурационному файлу haproxy.cfg. Этот файл определяет, как балансировать трафик между серверами (в нашем случае — контейнерами).

Пример файла:

Код ITЗагрузка примера кода…

Разбор:

  • Секция global/defaults задаёт логирование, режим HTTP и таймауты connect/client/server для всех последующих секций.
  • frontend http_front слушает :80 и по умолчанию отправляет трафик в backend http_back.
  • balance roundrobin распределяет запросы по очереди; server ... check помечает узлы с активной проверкой доступности.

Здесь:

  • frontend — это "вход" для трафика. Мы говорим HAProxy слушать порт 80.
  • backend — это "выход", куда HAProxy будет направлять запросы. Мы указали два сервера (app1 и app2), между которыми будет распределяться нагрузка.
  • balance roundrobin — алгоритм балансировки. Запросы будут отправляться по очереди на каждый сервер.

Запуск HAProxy в Docker

Нужно создать Docker Compose файл, чтобы запустить HAProxy вместе с контейнерами.

В файле docker-compose.yml нужно указать соответственно два контейнера с приложением (app1 и app2), запустить их на портах, и также дополнительно запустить haproxy:

Код ITЗагрузка примера кода…

Разбор:

  • Сервисы app1/app2 публикуют приложение на хост-портах 8081/8082; клиент снаружи ходит на HAProxy на :80.
  • Том ./haproxy.cfg:... подставляет конфиг в контейнер балансировщика; depends_on лишь упорядочивает старт, не ждёт readiness.
  • YAML чувствителен к отступам: каждый уровень вложенности — два пробела; ключи слева определяют структуру конфигурации.

Запуск

Запускаем всё, в нашем случае, через Docker Compose. После этого HAProxy начнёт принимать запросы на порту 80 и перенаправлять их на контейнеры app1 и app2. Похожий паттерн "несколько сервисов + reverse proxy" — стек №11 в галерее Compose.


Проверка работы

В нашем случае, достаточно открыть http://localhost и там можно будет увидеть, что запросы распределяются между контейнерами.

Для более сложных систем (например, Kubernetes) имеется возможность можно настроить HAProxy для автоматического обнаружения контейнеров через Consul.

Пример конфигурации для Consul:

backend http_back
balance roundrobin
server-template app 2 _app._tcp.service.consul resolvers consul resolve-prefer ipv4 check

Разбор:

  • server-template разворачивает динамический пул серверов по DNS Consul вместо статического списка IP.
  • resolvers и resolve-prefer ipv4 задают, откуда HAProxy берёт адреса инстансов при масштабировании.
  • check исключает из ротации узлы, не прошедшие health check.

Здесь HAProxy будет использовать DNS-записи для поиска доступных серверов.

Примерно по такому алгоритму и выполняется балансировка нагрузки. Готовые контейнеры запускаются довольно легко, если конфигурация корректна.


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

Какие алгоритмы использует балансировка нагрузки?


Round-robin (RR)

Запросы распределяются по очереди между всеми серверами без учёта их загрузки - если есть 3 сервера (A, B, C), запросы будут направлены в порядке A → B → C → A → B → C.

Когда подходит: однородные серверы, короткие запросы одинаковой стоимости, stateless API.

Риск: медленный узел получает ту же долю трафика, что и быстрый — растёт p95 latency всей системы.

Play ITЗагрузка интерактивного демо…


Least Connections (LC)

Запрос направляется на сервер с наименьшим количеством активных соединений, что определяется путём постоянного мониторинга состояния серверов.

Когда подходит: долгие запросы (отчёты, WebSocket), разная скорость обработки на узлах, смешанная нагрузка.

Идея: новый запрос идёт туда, где меньше "висящих" соединений, а не просто по кругу.

Play ITЗагрузка интерактивного демо…


Weighted Round-Robin (WRR)

Аналогично round-robin, но серверам присваиваются веса (например, мощные серверы получают больше запросов). Распределение будет по весу - сервер A (вес 3), сервер B (вес 2), сервер C (вес 1). Распределение будет A → A → A → B → B → C. Веса настраиваются вручную.

Когда подходит: в пуле смешаны машины разной мощности или постепенно вводят новый узел (низкий вес на канареечном сервере).

Play ITЗагрузка интерактивного демо…


Weighted Least Connections (WLC)

Weighted Least Connections (WLC) — это комбинация Least Connections и Weighted Round-Robin. Учитывает как количество активных соединений, так и вес серверов.

Play ITЗагрузка интерактивного демо…


IP Hash

IP Hash распределяет запросы на основе хеша IP-адреса клиента, к примеру, клиент с IP 192.168.1.1 всегда будет направлен на сервер A.

Когда подходит: нужна "липкость" без cookie (простые сессии в памяти узла). Минус: при падении узла клиенты с его IP-пулом переезжают на другой сервер и теряют локальную сессию; за NAT один внешний IP даёт перекос нагрузки.

Play ITЗагрузка интерактивного демо…


Random

Random направляет запросы на случайный сервер. Но здесь может быть неравномерная нагрузка.

Используют редко; на больших объёмах распределение выравнивается, на малых — возможны всплески на один узел.

Play ITЗагрузка интерактивного демо…


См. также


Основа по протоколу

Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.