Балансировка нагрузки (Load Balancing) — распределение входящих запросов между несколькими экземплярами сервиса. Для системного аналитика тема закрывает вопрос «какой алгоритм и на каком уровне зафиксировать в НФТ и ADR», а не «как настроить NGINX». Выбор стратегии завязан на 08.02 Нефункциональные требования (НФТ) — классификация и стандарты: пропускная способность, доступность, задержка и масштабируемость. Детали паттернов устойчивости и масштабирования — в 03.06.01 Архитектурные паттерны распределённых систем; порядок с ограничением трафика — в 03.06.03 Rate Limiting — управление пропускной способностью.
1. Суть темы
Балансировщик (Load Balancer, LB) стоит между клиентом и пулом бэкенд-экземпляров и решает, к какому экземпляру направить каждый запрос. Цели с точки зрения требований:
| Цель | Что фиксировать в спецификации |
|---|---|
| Равномерное использование ресурсов | Алгоритм и метрика «равномерности» — только для алгоритмов без affinity (см. §3.3–3.4) |
| Пропускная способность | Число экземпляров, лимит соединений на узел, горизонтальное масштабирование без смены клиентского endpoint |
| Задержка | Алгоритм, учитывающий latency (Least Time), если p95/p99 — ключевой KPI |
| Отказоустойчивость | Исключение из ротации узлов, не прошедших health check (unhealthy); время обнаружения сбоя |
| Горизонтальное масштабирование | Добавление/удаление экземпляров без перезагрузки LB и без простоя клиентов |
Глобальная vs локальная балансировка. Глобальная — между регионами или AZ (geo-DNS, anycast, cloud global LB): клиент попадает в «ближайший» дата-центр. Локальная — внутри кластера или AZ между экземплярами одного сервиса. В требованиях не смешивайте: «алгоритм Round Robin на ingress» и «geo-маршрутизация пользователя» — разные решения и разные владельцы (DNS vs платформа vs приложение). Для глобальной балансировки отдельно фиксируйте RPO/RTO между регионами и владельца политики geo/DNS.
Опорная цепочка ingress (согласована с 03.06.03 Rate Limiting — управление пропускной способностью; используйте её для трассировки требований):
[Client] → [Global/DNS] → [L4/L7 LB] → [API Gateway] → [Service Mesh / Client-side LB] → [Pod/Instance]- Rate Limiting обычно применяют на Gateway (или edge) до выбора конкретного бэкенда — отсекают «шумный» трафик до нагрузки на пул.
- Балансировка распределяет допущенный трафик между экземплярами; per-instance rate limit без глобального счётчика даёт N× лимит — это тема 03.06.03 Rate Limiting — управление пропускной способностью, не дублируем здесь.
2. Ключевые понятия
2.1. L4 и L7 — критерии выбора
Балансировщики работают на разных уровнях модели OSI; сетевой контекст — 07.07 Сетевые основы (подсети, протоколы и маршрутизация).
| Характеристика | L4 (Transport) | L7 (Application) |
|---|---|---|
| Что анализирует | IP, порт, протокол TCP/UDP | HTTP-заголовки, URL, cookies, gRPC metadata |
| Скорость | Выше, меньше задержка на прокси | Ниже из-за разбора содержимого |
| Протоколы | Любые TCP/UDP | HTTP/HTTPS, gRPC, WebSocket, SSE |
| Когда в требованиях | Базовая HA, не-TCP-трафик, минимальная задержка прокси | Маршрутизация по path/header, sticky по cookie, termination TLS на edge |
Правило для SRS: если нужна маршрутизация по URL, tenant, версии API или session affinity через cookie — указывайте L7; если достаточно «раздать TCP-соединения по пулу» — L4. Семантика gRPC load balancing — 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL).
WebSocket / SSE: длительное соединение требует sticky (cookie/hash) или L4 passthrough без разрыва на каждый hop; зафиксируйте idle timeout LB относительно ожидаемой длительности сессии и поведение при reconnect.
2.2. Классификация алгоритмов
| Тип | Принцип | Примеры |
|---|---|---|
| Статические | Правило без учёта текущей загрузки узлов | Round Robin, Weighted RR, Hash-based, Consistent Hashing |
| Динамические | Учитывают активные соединения, in-flight запросы, latency | Least Connections, Weighted LC, Least Time, Least Request, P2C |
Простой hash vs consistent hashing (для ADR): обычный hash перераспределяет все ключи при изменении размера пула; consistent hashing — только долю ключей, затронутых добавленным/удалённым узлом. В требованиях пишите «consistent hashing», если пул часто меняется (autoscaling, кеш) и недопустима массовая инвалидация; «IP hash / hash by key» — если состав пула стабилен и нужна sticky-сессия без динамики.
2.3. Статические алгоритмы
Round Robin — циклическая очередь. Подходит для однородных stateless-сервисов с короткими запросами одинаковой сложности.
Weighted Round Robin — пропорция по весам. Фиксируйте веса в ADR при разной мощности узлов или canary (10% на новую версию). Веса требуют пересмотра при изменении инфраструктуры; связь с выкатом — 05.04 DevOps и непрерывная поставка — влияние на анализ.
Hash-based (IP Hash, URL Hash, Generic Hash) — детерминированный выбор узла по ключу. Обеспечивает session affinity (sticky sessions): один ключ → один узел. Неравномерность по узлам ожидаема — fairness-метрики к hash не применяют.
Consistent Hashing — hash ring с виртуальными узлами; минимальное перераспределение при scale-out/in. Типичный выбор для распределённых кешей и stateful-маршрутизации при изменяемом пуле. Критерии приёмки — stickiness и поведение при resharding (§3.4), не max/min RPS.
2.4. Динамические алгоритмы
Least Connections — запрос на узел с наименьшим числом активных TCP-соединений (L4/L7). Эффективен, когда запросы разной длительности, но не минимизирует latency напрямую — медленный узел может держать мало соединений, но обрабатывать их долго.
Weighted Least Connections — сравнивают active_connections / weight. Для гетерогенного пула и запросов разной длительности.
Least Time — выбор по среднему времени ответа (TTFB или полный ответ). Используйте в NFR, если KPI — «минимальная задержка», а не «равномерность соединений».
Least Active / Least Request — считают незавершённые вызовы (HTTP in-flight, gRPC outstanding RPC), а не TCP-соединения. На L7 и в RPC (Envoy least request, gRPC client LB) это точнее Least Connections: одно keep-alive соединение может нести много параллельных запросов.
| Что считаем | Типичный контекст | Как писать в NFR |
|---|---|---|
| TCP-соединения | L4, long-lived connections | «least connections» |
| HTTP/gRPC in-flight | L7, REST/gRPC | «least outstanding requests» / «least active» |
| Latency | p95/p99 как KPI | «least response time» / «least time» |
P2C (Power of Two Choices) — случайно выбирают два узла, отправляют на менее загруженный. Компромисс между точностью и стоимостью полного сканирования пула; часто в client-side LB и крупных кластерах.
Adaptive / ML-балансировка — агрегирует CPU, память, latency и др. Для большинства корпоративных API достаточно WRR, WLC или Least Request с health checks. Adaptive оправдан при доказанной нестабильности простых алгоритмов и наличии измеримых KPI улучшения; иначе риск scope creep и непроверяемых NFR («адаптивная балансировка с ML» без метрик приёмки).
2.5. Session affinity (sticky sessions)
Sticky sessions нужны, когда состояние хранится на узле, а не во внешнем store.
| Механизм | Ограничение | Что указать в требованиях |
|---|---|---|
| IP Hash | За CDN/LB/Gateway виден IP прокси, не клиента | Ключ affinity: X-Forwarded-For, cookie, user_id — не «по IP клиента» без проверки топологии |
| Cookie-based (L7) | Стандарт для stateful за reverse proxy | Имя cookie, TTL, поведение при отсутствии cookie |
| Consistent hash by user_id | Предсказуемая привязка без cookie | Ключ и поведение при смене состава пула |
Следствия для приёмки: падение узла → сессии на нём теряются, если нет репликации; нужен ли внешний session store (Redis и т.п.) или переход на stateless + JWT. Альтернатива sticky — stateless-дизайн; это архитектурное решение, не настройка LB.
2.6. Health checks и graceful shutdown
| Тип | Смысл | Что фиксировать |
|---|---|---|
| Active | LB периодически шлёт probe (HTTP/TCP) | Интервал, timeout, порог «N failures → unhealthy», порог «M successes → healthy» |
| Passive | Решение по ошибкам реального трафика (5xx, timeout, latency spike) | Доля ошибок или порог latency для исключения; задержка реакции |
Когда passive обязателен в требованиях: probe не покрывает реальный трафик (нестандартные заголовки, только POST), узел «зелёный» по active, но отдаёт 5xx под нагрузкой, или нужна быстрая реакция без ожидания следующего probe. Часто фиксируют combo: active для базового мониторинга + passive для деградации под load.
Flapping: при нестабильном узле задайте hysteresis (разные пороги входа/выхода из пула) и минимальное время в unhealthy, иначе трафик «прыгает» между узлами.
Graceful shutdown / connection draining: при деплое или scale-in узел помечают draining — новые запросы не принимают, текущие дорабатывают. В NFR: «вывод экземпляра из пула ≤ X с без обрыва in-flight запросов»; связь с zero-downtime deploy и canary — 05.04 DevOps и непрерывная поставка — влияние на анализ.
2.7. Место LB в архитектуре
Ниже — детализация уровней опорной цепочки из §1 (не альтернативная схема). Полная цепочка с Global/DNS и Rate Limiting — в §1 и 03.06.03 Rate Limiting — управление пропускной способностью.
[Client] → [External LB] → [API Gateway] → [Microservices]
↓
[Service Discovery]
↓
[Client-side LB / Mesh]| Уровень | Роль | Владелец в требованиях | Примеры |
|---|---|---|---|
| Внешний LB | HA, TLS termination, L4/L7 перед gateway | Платформа / инфраструктура | Cloud NLB/ALB, hardware LB |
| API Gateway | L7-маршрутизация, affinity, интеграция с RL | Платформа или API-команда (уточнить в ADR) | См. 03.05.01 Виды интеграции (точка-точка, ESB, API-led) |
| Service Mesh | East-west между сервисами | Платформа; политики per-service — команда сервиса | Sidecar LB — 03.06.01 Архитектурные паттерны распределённых систем, 07.08 Контейнеризация и оркестрация (Docker, Kubernetes) |
| Client-side LB | Клиент выбирает экземпляр по списку из Service Discovery | Команда сервиса / интеграционный контракт | gRPC, Dubbo |
Многослойная балансировка: на пути запроса часто работают несколько LB (ingress RR + mesh/client-side RR). Итоговое распределение сложно предсказать и воспроизвести в тесте. В NFR указывайте алгоритм и метрику на конкретном уровне («fairness на pod за ingress ALB») либо описывайте end-to-end сценарий нагрузочного теста с фиксированной топологией.
Retry на другой узел после ошибки — ответственность gateway/mesh/client, не «алгоритма LB»; в спецификации разводите политику retry (idempotency — 03.06.01 Архитектурные паттерны распределённых систем) и правило выбора узла.
Kubernetes: Service + kube-proxy/IPVS — server-side LB; алгоритмы и ограничения — 07.08 Контейнеризация и оркестрация (Docker, Kubernetes). DNS round-robin без health checks — legacy-anti-pattern: клиент кэширует IP, мёртвые узлы остаются в ротации.
2.8. Сравнительная таблица алгоритмов
| Алгоритм | Тип | Учёт нагрузки | Учёт мощности | Sticky | Метрика приёмки | Лучшее применение |
|---|---|---|---|---|---|---|
| Round Robin | Статический | Нет | Нет | Нет | Fairness (RPS) | Однородные stateless, короткие запросы |
| Weighted RR | Статический | Нет | Да | Нет | Доля трафика по весам / canary | Разномощные узлы, canary |
| IP / URL Hash | Статический | Нет | Нет | Да | Stickiness % | Affinity при стабильном пуле |
| Consistent Hashing | Статический | Нет | Нет | Да | Stickiness %; resharding | Кеш, частый scale-out/in |
| Least Connections | Динамический | Да (TCP) | Нет | Нет | Fairness (connections) | Long-lived / разная длительность |
| Weighted LC | Динамический | Да | Да | Нет | Fairness с учётом весов | Гетерогенный пул |
| Least Time | Динамический | Да (latency) | Да | Нет | p95/p99 latency | KPI — минимальная задержка |
| Least Request / Active | Динамический | Да (in-flight) | Нет | Нет | Fairness (in-flight) | L7, gRPC |
| P2C | Динамический | Да | Нет | Нет | Fairness (approx.) | Большие пулы, client-side |
| Adaptive | Динамический | Да (много метрик) | Да | Нет* | Заданные KPI ADR | Только при обоснованных KPI |
*Adaptive не даёт sticky «из коробки»; affinity задаётся отдельно (hash/cookie), как и для других не-hash алгоритмов.
3. Как применяется в работе аналитика
3.1. Вопросы для сбора требований
| Вопрос | Что определяет |
|---|---|
| Stateless или stateful? | RR / Least Request vs sticky / external session store |
| Одинакова ли мощность узлов? | Веса (WRR, WLC) |
| KPI — fairness или latency? | Least Connections vs Least Time |
| Нужна session affinity? | Cookie / hash key; не IP Hash за CDN без X-Forwarded-For |
| Как часто меняется пул? | Consistent hashing vs простой hash |
| Протоколы и уровень? | L4 vs L7; WebSocket/SSE — sticky или passthrough — §2.1 |
| Сколько уровней LB на пути запроса? | Где измеряем fairness / affinity — один уровень или end-to-end — §2.7 |
| Топология (CDN, gateway, mesh)? | Где именно балансируем — 03.01.04 Интерфейсы и интеграционные взаимодействия |
| Глобальная vs локальная? | Geo/DNS, RPO/RTO между регионами, владелец политики |
| Поведение при падении узла? | Health checks (active/passive/combo), draining; retry — gateway/mesh, idempotency — 03.06.01 Архитектурные паттерны распределённых систем |
| Связка с rate limiting? | RL на gateway до LB к бэкендам — 03.06.03 Rate Limiting — управление пропускной способностью |
| Canary / blue-green? | WRR-веса, draining, доля трафика на версию — 05.04 DevOps и непрерывная поставка — влияние на анализ |
| Кто владелец локального L7? | Платформа (shared ingress) vs команда сервиса (dedicated route) |
3.2. Где фиксировать в артефактах
| Артефакт | Что класть |
|---|---|
| NFR (10.01.12 Шаблон нефункциональных требований (NFR), 02.03.03 Спецификация требований (SRS, Use Case, User Story)) | Алгоритм на named уровне, L4/L7, health checks (active/passive), время исключения unhealthy, affinity, метрики приёмки, согласованные с алгоритмом |
| ADR (10.01.13 Шаблон архитектурного решения (ADR)) | Выбор алгоритма, отвергнутые альтернативы, ключ affinity, trade-off sticky vs stateless, уровень измерения |
| Интеграционная спецификация | Client-side LB; политика retry/failover на другой узел (gateway/mesh); stacked LB — какой уровень отвечает за fairness |
Правило привязки метрики к алгоритму: не смешивайте в одном NFR список алгоритмов с единым KPI fairness. Для RR / Least Request / Least Connections — max/min RPS или connections между здоровыми узлами. Для hash / sticky — stickiness %, hot-spot допустимость, поведение при resharding. Для WRR/canary — доля трафика на версию (± допуск), не fairness между pod одной версии.
3.3. Примеры формулировок
User Story (Least Connections — корректное обоснование):
Как владелец API, я хочу, чтобы запросы распределялись алгоритмом Least Connections, чтобы узлы с меньшим числом активных соединений получали новые запросы и ни один экземпляр не накапливал долгие соединения непропорционально остальным.
User Story (Least Time — если KPI latency):
Как владелец API, я хочу балансировку по наименьшему времени ответа, чтобы p95 latency оставалась в пределах SLA при неоднородной нагрузке на экземпляры.
Пример NFR (fairness — Round Robin / Least Request на ingress):
На уровне L7 ingress ALB сервис
orders-apiиспользует алгоритм Least Request. Узел, не прошедший active health check (интервал 5 с, 2 failures → unhealthy), исключается из ротации не более чем за 5 с. При scale-in экземпляр переводится в draining: новые запросы не направляются, in-flight завершаются в течение 30 с. Коэффициент неравномерности между здоровыми узлами (max RPS / min RPS) при steady load однородных запросов ≤ 1,2.
Пример NFR (affinity — consistent hash, отдельный блок):
Для маршрута
/api/v1/tenant/*ingress применяет consistent hash по заголовкуX-Tenant-Id. ≥ 99% запросов одного tenant_id направляются на один pod при неизменном пуле. При добавлении pod не более 1/N ключей переназначается (N — новый размер пула). Падение pod: запросы затронутых tenant получают 503 сRetry-After; idempotent GET — retry на другой узел через gateway.
Пример NFR (health checks — combo):
Помимо active probe каждые 5 с, балансировщик исключает узел по passive критерию: ≥ 5% ответов 5xx или p95 latency > 2 с за скользящее окно 30 с.
3.4. Критерии приёмки (нагрузочное тестирование)
Критерии оформляйте по 02.04.02 Критерии приёмки; нагрузочная проверка NFR — часть V&V (08.03 Тестирование требований (статическое тестирование), нагрузочное как проверка НФТ).
| Критерий | Когда применять | Что проверять |
|---|---|---|
| Fairness | RR, Least Connections/Request, Least Time — без affinity | max/min RPS или active connections между узлами при однородных запросах; уровень измерения — как в NFR |
| Traffic split (canary/WRR) | Weighted RR, canary, blue-green | Доля запросов на версию/v2 в пределах ±X% от заданного веса |
| Failover (active) | Любой алгоритм с active probe | Время исключения unhealthy; отсутствие 5xx после исключения (с учётом draining) |
| Failover (passive/combo) | Passive или combo в NFR | Исключение при инъекции 5xx/latency spike без ожидания следующего active probe; пороги из NFR |
| Latency | Least Time | p95/p99 при N экземплярах vs baseline одного экземпляра |
| Affinity | Hash, cookie, consistent hash | ≥99% запросов одного ключа на один узел; при падении узла — явное ожидаемое поведение (re-login, failover на store, 503) |
| Resharding | Consistent hash, autoscaling | Доля переназначенных ключей при scale-out/in — в пределах ADR |
| Stacked LB | Несколько уровней балансировки | End-to-end сценарий с зафиксированной топологией; не дублировать fairness на каждом hop без обоснования |
4. Типовые ошибки и ограничения
| Ошибка | Почему плохо | Как избежать |
|---|---|---|
| Fairness-KPI для hash/sticky | Неравномерность по определению; NFR непроверяем или ложно «красный» | Метрики stickiness / traffic split — §3.2–3.3 |
| Два независимых RR (ingress + mesh) | Распределение непредсказуемо; тесты не воспроизводят prod | Один уровень ответственности в NFR или end-to-end тест — §2.7 |
| Один алгоритм на всё | Разные эндпоинты — разная длительность и state | Route-specific политики на L7 |
| Игнорирование health checks | Трафик на мёртвые узлы | Active + passive/combo, пороги, hysteresis — §2.6, §3.4 |
| Только active в NFR при нужном passive | Probe «зелёный», реальный трафик падает | Combo или passive для деградации под load — §2.6 |
| Sticky без необходимости | Hot spot, сложность failover | Stateless + JWT или внешний session store |
| IP Hash за CDN/gateway | Affinity к одному gateway, не к пользователю | Cookie или hash по business key |
| Least Connections «для latency» | Алгоритм не оптимизирует время ответа | Least Time или Least Request + мониторинг p95 |
| DNS round-robin как LB | Нет health checks, кэш DNS | Настоящий LB или Service Discovery |
| Adaptive/ML без KPI | Непроверяемое NFR | WRR/WLC/Least Request + измеримые метрики |
| Нет draining при деплое | Обрыв in-flight, 502 при rollout | Graceful shutdown в NFR и runbook — 05.04 DevOps и непрерывная поставка — влияние на анализ |
| Retry в «алгоритме LB» | Размыта ответственность gateway vs сервис | Retry/failover — интеграционная спецификация; idempotency — 03.06.01 Архитектурные паттерны распределённых систем |
| LB без учёта безопасности | DDoS, oversized body | Edge/WAF, лимиты — 03.05.05 Безопасность API, 08.07 Основы кибербезопасности для системного аналитика |
Связи с другими разделами базы
- Паттерны масштабирования и HA — 03.06.01 Архитектурные паттерны распределённых систем
- Rate Limiting и порядок в ingress — 03.06.03 Rate Limiting — управление пропускной способностью
- API Gateway и топология интеграции — 03.05.01 Виды интеграции (точка-точка, ESB, API-led), 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL)
- Уровни архитектуры и view — 03.01.01 Понятие архитектуры ИС и её виды (бизнес-, системная, техническая), 03.01.04 Интерфейсы и интеграционные взаимодействия
- НФТ, SLA и шаблон NFR — 08.02 Нефункциональные требования (НФТ) — классификация и стандарты, 10.01.12 Шаблон нефункциональных требований (NFR)
- Спецификация и критерии приёмки — 02.03.03 Спецификация требований (SRS, Use Case, User Story), 02.04.02 Критерии приёмки
- V&V и нагрузочная проверка NFR — 08.03 Тестирование требований (статическое тестирование)
- DevOps, canary, draining — 05.04 DevOps и непрерывная поставка — влияние на анализ
- Kubernetes и Service Discovery — 07.08 Контейнеризация и оркестрация (Docker, Kubernetes)
- L4/L7, протоколы — 07.07 Сетевые основы (подсети, протоколы и маршрутизация)
- ADR — 10.01.13 Шаблон архитектурного решения (ADR)
- Безопасность на edge — 03.05.05 Безопасность API, 08.07 Основы кибербезопасности для системного аналитика
Источники и дополнительные материалы
Книги
- Chris Richardson — Microservices Patterns (маршрутизация и балансировка в микросервисах)
- Sam Newman — Building Microservices (Service Discovery, client-side LB)
Онлайн-ресурсы и документация
- NGINX — HTTP Load Balancing — https://nginx.org/en/docs/http/load_balancing.html
- AWS — Application Load Balancer — https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html
- Envoy — Load Balancing — https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/load_balancing
- Kubernetes — Service and kube-proxy — https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
- Apache Dubbo — Load Balance — https://dubbo.apache.org/en/docs3-v2/java-sdk/reference-manual/loadbalance/loadbalance/
- Apache APISIX — Gateway vs Load Balancer — https://apisix.apache.org/docs/apisix/terminology/gateway/