Балансировка нагрузки и маршрутизация в Nginx и Kubernetes: стратегии для высоконагруженных систем | AdminWiki

Балансировка нагрузки и маршрутизация в Nginx и Kubernetes: стратегии для высоконагруженных систем

27 августа 2026 10 мин. чтения

Введение: зачем нужна балансировка нагрузки и маршрутизация

Балансировка нагрузки распределяет входящий трафик между несколькими серверами или подами, чтобы ни один узел не стал узким местом. Маршрутизация направляет запросы на нужный бэкенд на основе URL, заголовков или cookies. В высоконагруженных системах эти механизмы работают вместе: балансировка обеспечивает горизонтальное масштабирование, маршрутизация - гибкое управление версиями и изоляцию сервисов.

Nginx решает задачу на уровне L7, работая как reverse proxy с широкими возможностями настройки upstream-групп. Kubernetes распределяет трафик внутри кластера через Service и kube-proxy, а внешний HTTP-трафик обрабатывает Ingress-контроллер. Эта статья дает готовые конфигурации для обоих инструментов: алгоритмы round-robin, least_conn, ip_hash, health check, маршрутизацию по URL и заголовкам, canary-развертывания.

Материал ориентирован на DevOps-инженеров и системных администраторов, которые настраивают продакшен-окружения. Все примеры проверены на актуальных версиях Nginx и Kubernetes в 2026 году.

Алгоритмы балансировки нагрузки: round-robin, least_conn, ip_hash

Выбор алгоритма определяет, как запросы распределяются между бэкендами. Ошибка здесь приводит к перегрузке отдельных серверов, потере сессий или неэффективному использованию ресурсов. Разберем три базовых алгоритма, доступных в Nginx и частично в Kubernetes.

Round-robin: равномерное распределение

Round-robin циклически отправляет каждый новый запрос следующему серверу в списке. Первый запрос уходит на server1, второй на server2, третий на server3, затем цикл повторяется. Это алгоритм по умолчанию в Nginx.

Для серверов разной производительности задаются веса. Параметр weight указывает, во сколько раз сервер получает больше запросов. Сервер с weight=3 обработает три запроса из четырех при втором сервере с weight=1.

Ограничение round-robin проявляется при длинных сессиях. Если пользователь держит WebSocket-соединение или выполняет многошаговую транзакцию, следующий запрос может попасть на другой сервер, где нет его контекста. Для таких сценариев нужны least_conn или ip_hash.

Least_conn: учет текущей нагрузки

Least_conn выбирает сервер с наименьшим количеством активных соединений. Алгоритм учитывает не только факт запроса, но и его длительность. Сервер, обрабатывающий долгие запросы, получает меньше новых соединений, пока не освободит ресурсы.

Этот подход оптимален для приложений с неравномерной нагрузкой: API с тяжелыми вычислениями, файловые хранилища, стриминговые сервисы. Least_conn предотвращает ситуацию, когда round-robin отправляет новый запрос на сервер, который уже перегружен длительной операцией.

В Nginx least_conn активируется директивой least_conn внутри upstream-блока. Веса также поддерживаются: сервер с большим весом получает больше соединений при прочих равных.

Ip_hash: привязка к клиенту

Ip_hash вычисляет хэш от IP-адреса клиента и на основе хэша выбирает сервер. Все запросы с одного IP попадают на один и тот же бэкенд. Это решает проблему сохранения сессии без внешнего хранилища.

Алгоритм полезен для приложений, которые хранят состояние локально на сервере: файлы сессий, кэш, временные данные. Пользователь всегда возвращается на тот же узел, где остались его данные.

Недостаток ip_hash - чувствительность к изменению списка серверов. При добавлении или удалении узла хэш-таблица пересчитывается, и часть клиентов перенаправляется на другие серверы. Это приводит к потере локальных сессий. Для стабильности можно использовать параметр consistent в Nginx, который минимизирует перераспределение при изменении набора серверов.

АлгоритмПринципПлюсыМинусыКогда использовать
round-robinЦиклический переборПростота, предсказуемостьНе учитывает нагрузку и сессииStateless-приложения, однородные серверы
least_connМинимум активных соединенийАдаптация к длительности запросовСложнее отладкаДолгие запросы, неравномерная нагрузка
ip_hashХэш IP-адреса клиентаСохранение сессии без внешнего хранилищаПерераспределение при изменении пулаStateful-приложения, sticky sessions

Настройка балансировки нагрузки в Nginx

Nginx реализует балансировку через блок upstream, который определяет группу бэкенд-серверов. Директива proxy_pass в location направляет запросы на эту группу. Ниже - рабочие конфигурации для каждого алгоритма.

Базовая конфигурация upstream

http {
    upstream backend {
        server 10.0.1.10:8080;
        server 10.0.1.11:8080;
        server 10.0.1.12:8080;
    }

    server {
        listen 80;
        server_name api.example.com;

        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

Блок upstream backend перечисляет три сервера. Без явного указания алгоритма Nginx использует round-robin. Директивы proxy_set_header передают бэкенду информацию об исходном клиенте, что критично для логирования и корректной работы приложений.

Настройка health check

Пассивные проверки работоспособности настраиваются параметрами max_fails и fail_timeout. Если сервер не отвечает max_fails раз за fail_timeout, он временно исключается из ротации.

upstream backend {
    server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.12:8080 max_fails=3 fail_timeout=30s backup;
}

Параметр backup помечает резервный сервер. Он получает трафик только когда все основные узлы недоступны. Это дешевый способ обеспечить failover без дополнительного оборудования.

Активные health check доступны в коммерческой версии Nginx Plus через директиву health_check. Для open-source Nginx можно использовать сторонний модуль ngx_http_upstream_check_module или реализовать проверки через внешний скрипт, который обновляет конфигурацию и перезагружает Nginx.

Примеры для каждого алгоритма

Round-robin с весами:

upstream backend {
    server 10.0.1.10:8080 weight=3;
    server 10.0.1.11:8080 weight=1;
}

Least_conn:

upstream backend {
    least_conn;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

Ip_hash с консистентным хэшированием:

upstream backend {
    ip_hash consistent;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

Подробнее о настройке upstream-групп, keepalive-соединений и автоматическом восстановлении бэкендов читайте в руководстве по отказоустойчивости Nginx.

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

Kubernetes балансирует трафик на нескольких уровнях. Service распределяет запросы между подами внутри кластера, Ingress управляет внешним HTTP-трафиком и маршрутизацией по URL. Понимание этих уровней необходимо для построения надежной архитектуры.

Service и kube-proxy

Service - это абстракция, которая определяет логический набор подов и политику доступа к ним. Тип ClusterIP создает внутренний виртуальный IP, доступный только внутри кластера. NodePort открывает порт на каждом узле, LoadBalancer создает внешний балансировщик у облачного провайдера.

kube-proxy - компонент, который реализует правила балансировки на каждом узле. В режиме iptables он создает правила NAT для распределения трафика. Режим IPVS использует более производительный механизм виртуального сервера Linux с поддержкой алгоритмов round-robin, least-connection и других. Для кластеров с большим количеством сервисов IPVS предпочтительнее из-за меньшей задержки и лучшей масштабируемости.

apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  selector:
    app: api
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP

Селектор app: api связывает Service с подами, имеющими эту метку. kube-proxy автоматически обновляет правила при добавлении или удалении подов. Kubernetes использует EndpointSlice для отслеживания актуальных адресов подов, что ускоряет обновление правил балансировки в крупных кластерах.

Ingress для маршрутизации HTTP

Ingress - это API-объект, который описывает правила маршрутизации HTTP-трафика к сервисам. Ingress-контроллер (Nginx, Traefik, HAProxy) реализует эти правила. Пример маршрутизации по путям:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /users
            pathType: Prefix
            backend:
              service:
                name: users-service
                port:
                  number: 80
          - path: /orders
            pathType: Prefix
            backend:
              service:
                name: orders-service
                port:
                  number: 80

Запросы к /users направляются в users-service, к /orders - в orders-service. Это позволяет разбивать монолит на микросервисы без изменения внешнего API. Готовые конфигурации для Nginx, Traefik и Kubernetes Ingress с тюнингом на 10k соединений собраны в руководстве по маршрутизации процессов.

Маршрутизация на основе URL, заголовков и cookies

Балансировка распределяет трафик равномерно, маршрутизация направляет его избирательно. Комбинация этих подходов позволяет выделять ресурсы под конкретные сервисы, проводить A/B-тесты и постепенно выкатывать новые версии.

Маршрутизация по URL в Nginx

Директивы location сопоставляют URI запроса с нужным upstream. Пример разделения API и статики:

upstream api_backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
}

upstream static_backend {
    server 10.0.2.10:80;
    server 10.0.2.11:80;
}

server {
    listen 80;

    location /api/ {
        proxy_pass http://api_backend;
    }

    location /static/ {
        proxy_pass http://static_backend;
    }

    location / {
        proxy_pass http://static_backend;
    }
}

Запросы с префиксом /api/ уходят на серверы приложений, остальные - на серверы статики. Это изолирует нагрузки и позволяет масштабировать каждую группу независимо.

Маршрутизация по заголовкам и cookies

Директива map создает переменную на основе значения заголовка или cookie, а if или proxy_pass с переменной направляет трафик. Пример A/B-тестирования по cookie:

map $cookie_experiment $backend_group {
    default     "stable";
    "beta"      "beta";
}

upstream stable_backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
}

upstream beta_backend {
    server 10.0.2.10:8080;
}

server {
    listen 80;

    location / {
        proxy_pass http://${backend_group}_backend;
    }
}

Пользователи с cookie experiment=beta попадают на бета-версию, остальные - на стабильную. Это позволяет тестировать новые функции на ограниченной аудитории без риска для основной массы пользователей.

Для маршрутизации по заголовкам используется map с переменной $http_<header_name>. Например, $http_x_version для заголовка X-Version.

Canary deployments в Kubernetes

Canary-развертывание постепенно переводит трафик на новую версию. В Kubernetes это реализуется через Ingress с аннотациями контроллера. Пример для Nginx Ingress Controller:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-v2
                port:
                  number: 80

Аннотация canary-weight: "10" отправляет 10% трафика на сервис app-v2. Остальные 90% идут на основной сервис, описанный в другом Ingress без canary-аннотаций. Вес можно увеличивать постепенно, контролируя метрики новой версии.

Обеспечение отказоустойчивости

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

Health check в Nginx

Пассивные проверки настраиваются через max_fails и fail_timeout. Активные проверки в open-source Nginx требуют сторонних модулей. Коммерческий Nginx Plus включает директиву health_check:

upstream backend {
    zone backend 64k;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
}

server {
    listen 80;

    location / {
        proxy_pass http://backend;
        health_check interval=5s fails=3 passes=2;
    }
}

Директива zone выделяет разделяемую память для хранения состояния серверов. health_check опрашивает бэкенды каждые 5 секунд, помечает сервер неработающим после 3 неудачных проверок и возвращает в ротацию после 2 успешных.

Параметр proxy_next_upstream определяет, при каких ошибках Nginx перенаправляет запрос на следующий сервер:

location / {
    proxy_pass http://backend;
    proxy_next_upstream error timeout http_502 http_503 http_504;
    proxy_next_upstream_tries 2;
    proxy_next_upstream_timeout 10s;
}

Запрос повторяется на другом бэкенде при ошибке соединения, таймауте или ответах 502/503/504. Максимум две попытки за 10 секунд, чтобы не создавать каскадную нагрузку.

Health check в Kubernetes

Kubernetes использует три типа проб. Liveness probe проверяет, жив ли контейнер, и перезапускает его при сбое. Readiness probe определяет, готов ли под принимать трафик, и исключает его из Service при неудаче. Startup probe защищает медленно стартующие приложения от ложных срабатываний liveness.

apiVersion: v1
kind: Pod
metadata:
  name: api-pod
spec:
  containers:
    - name: api
      image: api:1.0
      startupProbe:
        httpGet:
          path: /health
          port: 8080
        failureThreshold: 30
        periodSeconds: 10
      livenessProbe:
        httpGet:
          path: /health
          port: 8080
        initialDelaySeconds: 0
        periodSeconds: 10
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        periodSeconds: 5

Startup probe дает приложению до 300 секунд на запуск (30 попыток с интервалом 10 секунд). После успешного старта активируются liveness и readiness. Readiness проверяется каждые 5 секунд - при неудаче kube-proxy удаляет под из правил балансировки.

Мониторинг и отладка

Без метрик невозможно определить, правильно ли распределяется нагрузка. Nginx предоставляет модуль stub_status с базовой статистикой. Kubernetes экспортирует метрики через kube-state-metrics и cAdvisor. Prometheus собирает данные, Grafana визуализирует их.

Включение stub_status в Nginx:

server {
    listen 127.0.0.1:8080;

    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        deny all;
    }
}

Эндпоинт отдает количество активных соединений, принятых и обработанных запросов, число чтений и записей. Эти цифры показывают общую нагрузку на балансировщик.

Для анализа распределения по бэкендам нужны расширенные метрики. Nginx Plus предоставляет API с детализацией по каждому серверу upstream. В open-source версии можно парсить access-логи и агрегировать данные по upstream_addr.

В Kubernetes ключевые метрики: количество подов в статусе Ready, latency запросов через Ingress, ошибки 5xx, utilization CPU и памяти по подам. Аномалии в этих метриках указывают на проблемы с балансировкой или конфигурацией проб.

Типовой дашборд Grafana для балансировки включает: RPS по сервисам, latency по перцентилям (p50, p95, p99), количество 5xx ответов, число активных соединений на бэкенд, статус health check. Сравнение этих метрик до и после изменения конфигурации помогает оценить эффект.

Безопасность при балансировке

Балансировщик - первая точка входа в инфраструктуру, поэтому его защита критична. Терминация TLS на Nginx или Ingress-контроллере снимает нагрузку шифрования с бэкендов и централизует управление сертификатами.

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate /etc/nginx/ssl/api.crt;
    ssl_certificate_key /etc/nginx/ssl/api.key;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://backend;
    }
}

Rate limiting защищает бэкенды от DDoS и резких всплесков трафика. Директива limit_req_zone определяет зону с лимитом, limit_req применяет ее к location:

http {
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;

    server {
        location /api/ {
            limit_req zone=api_limit burst=50 nodelay;
            proxy_pass http://api_backend;
        }
    }
}

Лимит 100 запросов в секунду с IP-адреса с burst 50 позволяет кратковременные всплески, но блокирует устойчивые атаки. Для Kubernetes аналогичные функции выполняют аннотации Ingress-контроллера: nginx.ingress.kubernetes.io/limit-rps, limit-burst-multiplier.

Доступ к административным эндпоинтам (stub_status, health check API) ограничивается по IP через allow и deny. Внутренний трафик между балансировщиком и бэкендами изолируется в приватной сети или через mutual TLS.

Заключение

Выбор стратегии балансировки зависит от характера нагрузки. Stateless-приложения работают эффективно с round-robin. Долгие запросы требуют least_conn. Локальные сессии - ip_hash. В Kubernetes базовую балансировку обеспечивает Service, гибкую маршрутизацию - Ingress.

Внедряйте health check на всех уровнях: пассивные проверки в Nginx, readiness и liveness пробы в Kubernetes. Настройте таймауты и повторные попытки через proxy_next_upstream. Собирайте метрики с первого дня эксплуатации - без них отладка проблем с распределением трафика превращается в гадание.

Для углубления в тему изучите сравнение алгоритмов балансировки с таблицей выбора под архитектуру и разбор архитектур Active/Passive и Active/Active. Если вы разворачиваете инфраструктуру для тестирования этих конфигураций, облачные серверы Timeweb Cloud предоставляют готовую среду с Kubernetes и гибким масштабированием ресурсов.

Поделиться:
Сохранить гайд? В закладки браузера