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

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

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

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

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

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

image-2.png

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

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

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

Аппаратные балансировщики представляют собой специализированное оборудование, разработанное для высокопроизводительной балансировки, к примеру, 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.

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

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

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

  1. Установить HAProxy через пакетный менеджер или запустить его в отдельном контейнере через Docker:
docker pull haproxy:latest
  1. Конфигурация. HAProxy работает по конфигурационному файлу haproxy.cfg. Этот файл определяет, как балансировать трафик между серверами (в нашем случае — контейнерами).

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

global
log stdout format raw local0

defaults
mode http
timeout connect 5s
timeout client 30s
timeout server 30s

frontend http_front
bind *:80
default_backend http_back

backend http_back
balance roundrobin
server app1 192.168.1.101:80 check
server app2 192.168.1.102:80 check

Здесь:

  • frontend — это «вход» для трафика. Мы говорим HAProxy слушать порт 80.
  • backend — это «выход», куда HAProxy будет направлять запросы. Мы указали два сервера (app1 и app2), между которыми будет распределяться нагрузка.
  • balance roundrobin — алгоритм балансировки. Запросы будут отправляться по очереди на каждый сервер.
  1. Запуск HAProxy в Docker. Нужно создать Docker Compose файл, чтобы запустить HAProxy вместе с контейнерами. В файле docker-compose.yml нужно указать соответственно два контейнера с приложением (app1 и app2), запустить их на портах, и также дополнительно запустить haproxy:
version: '3'
services:
app1:
image: your-app-image
ports:
- "8081:80"

app2:
image: your-app-image
ports:
- "8082:80"

haproxy:
image: haproxy:latest
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
ports:
- "80:80"
depends_on:
- app1
- app2
  1. Запуск. Запускаем всё, в нашем случае, через Docker Compose. После этого HAProxy начнёт принимать запросы на порту 80 и перенаправлять их на контейнеры app1 и app2.
  2. Проверка работы. В нашем случае, достаточно открыть 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

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

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

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

  1. Round-robin (RR). Запросы распределяются по очереди между всеми серверами без учёта их загрузки - если есть 3 сервера (A, B, C), запросы будут направлены в порядке A → B → C → A → B → C.
  2. Least Connections (LC). Запрос направляется на сервер с наименьшим количеством активных соединений, что определяется путём постоянного мониторинга состояния серверов.
  3. Weighted Round-Robin (WRR). Аналогично round-robin, но серверам присваиваются веса (например, мощные серверы получают больше запросов). Распределение будет по весу - сервер A (вес 3), сервер B (вес 2), сервер C (вес 1). Распределение будет A → A → A → B → B → C. Веса настраиваются вручную.
  4. Weighted Least Connections (WLC) — это комбинация Least Connections и Weighted Round-Robin. Учитывает как количество активных соединений, так и вес серверов.
  5. IP Hash распределяет запросы на основе хеша IP-адреса клиента, к примеру, клиент с IP 192.168.1.1 всегда будет направлен на сервер A.
  6. Random направляет запросы на случайный сервер. Но здесь может быть неравномерная нагрузка.