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-балансировщики облака | Система в облаке |