Перейти к содержанию

Load Balancer

Load balancer - распределяет входящие запросы между несколькими инстансами одного сервиса. Клиент видит один адрес, а за ним работают N копий, и балансировщик решает, какая из них ответит.

Зачем:

  • горизонтальное масштабирование: не хватает одного инстанса - ставишь ещё копии за тот же адрес
  • отказоустойчивость: упавший инстанс выпадает из ротации по health check, клиент этого не замечает
  • выкладка без простоя: инстансы обновляют по одному, остальные в это время держат трафик

Note

Балансировщик ничего не знает про API: ни клиентов, ни токенов, ни смысла маршрутов. Этим он отличается от API Gateway. Обычно они стоят друг за другом: балансировщик раскидывает трафик по инстансам gateway.


L4 и L7

L4 (транспортный) L7 (прикладной)
Что видит IP, порт, TCP- или UDP-соединение HTTP: путь, заголовки, cookie, метод
Что балансирует соединение целиком уходит на один инстанс каждый запрос отдельно
TLS пропускает насквозь, расшифровывает сервер может терминировать TLS сам
Скорость быстрее, содержимое пакетов не разбирает медленнее, разбирает HTTP
Что ещё умеет только распределять соединения маршрут по пути и хосту, retry, липкость по cookie
Примеры AWS NLB, HAProxy в режиме tcp, IPVS, kube-proxy NGINX, HAProxy в режиме http, Envoy, AWS ALB

Алгоритмы

Алгоритм Как выбирает инстанс Когда брать В NGINX
Round robin по кругу, по очереди запросы примерно одинаковые по умолчанию
Weighted round robin по кругу, но мощному инстансу чаще инстансы разной мощности server ... weight=3
Least connections у кого меньше активных соединений запросы сильно разные по длительности least_conn
IP hash хэш IP клиента -> всегда один и тот же инстанс нужна липкость без cookie ip_hash
Consistent hashing хэш ключа (URI, id). При смене числа инстансов переезжает малая часть ключей кэши и шардированные данные hash ... consistent
Power of two choices два случайных инстанса, из них менее загруженный много балансировщиков без общего состояния random two least_conn

Конфиги upstream с этими алгоритмами, см. Nginx.


Health checks

  • Активные - балансировщик сам периодически дёргает /health у каждого инстанса. Не ответил N раз - выводит из ротации, снова ответил - возвращает. Так умеют HAProxy, Envoy, NGINX Plus
  • Пассивные - балансировщик смотрит на реальные ответы: после N ошибок подряд инстанс выключается на время. В open source NGINX есть только они: max_fails и fail_timeout

В Kubernetes ту же роль играет readiness-проба: под, который её не прошёл, убирают из Service (см. Discovery в Kubernetes).


Sticky sessions

Sticky session - все запросы одного клиента идут на один и тот же инстанс: по cookie балансировщика или по хэшу IP.

  • нужна, когда сессия лежит в памяти инстанса
  • ломает равномерность: тяжёлые клиенты перегружают свой инстанс
  • инстанс упал - сессии на нём потеряны

Лучше вынести сессию в общее хранилище (Redis) и сделать сервис stateless, тогда липкость не нужна (см. Масштабирование).


Где стоит балансировщик

  • DNS - имя отдаёт несколько IP, клиенты расходятся по ним. Просто, но из-за кэша DNS мёртвый адрес быстро не убрать. На этом же уровне работает GSLB: выбирает ближний или живой дата-центр
  • Облачный или аппаратный перед системой - AWS ALB и NLB, F5, Service типа LoadBalancer в Kubernetes
  • Программный перед сервисом - NGINX, HAProxy, Envoy
  • На клиенте - клиент сам берёт список инстансов из service discovery и выбирает: Spring Cloud LoadBalancer, балансировка в клиенте gRPC
  • Внутри кластера - Service в Kubernetes: kube-proxy распределяет соединения по подам на L4

Грабли

  • Балансировщик - single point of failure. Ставят пару, активный и резервный, с общим виртуальным IP (keepalived, VRRP), или берут облачный, у которого отказоустойчивость внутри.
  • Долгие соединения на L4. gRPC и HTTP/2 держат одно соединение и гонят по нему все запросы. L4-балансировщик раскидывает соединения, а не запросы, и весь поток клиента уходит в один инстанс. Нужен L7-балансировщик или балансировка на клиенте.
  • IP клиента теряется. Сервис видит IP балансировщика. Настоящий передают в заголовке X-Forwarded-For (L7) или через PROXY protocol (L4).
  • Холодный старт. Новый инстанс сразу получает полную долю трафика, пока JVM не прогрелась. Помогает slow start: доля нового инстанса растёт постепенно (HAProxy, Envoy, NGINX Plus).

Технологии

Технология Уровень Что это Когда брать
NGINX L7, L4 через stream Reverse proxy и балансировщик Простой вход: TLS и балансировка по upstream
HAProxy L4 и L7 Специализированный балансировщик Высокая нагрузка, тонкая настройка, активные проверки
Envoy L4 и L7 Прокси, конфиг меняется на лету через API Kubernetes, gRPC, основа gateway и mesh
Traefik L4 и L7 Reverse proxy с авто-конфигом из Docker и Kubernetes Docker Compose, небольшой Kubernetes
IPVS, keepalived L4 Балансировка в ядре Linux и общий виртуальный IP Свои серверы, отказоустойчивая пара балансировщиков
Kubernetes Service, MetalLB L4 Балансировка по подам, внешний IP на своём железе Кластер Kubernetes
AWS ALB и NLB, другие облачные L7 и L4 Managed-балансировщики облака Система в облаке