Базовая конфигурация upstream
upstream backend {
# Round-robin по умолчанию
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080 weight=2; # В 2 раза больше запросов
# Запасной сервер
server 10.0.0.4:8080 backup;
keepalive 32; # Persistent connections
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout;
}
}
Алгоритмы балансировки
| Алгоритм | Директива | Применение |
|---|---|---|
| Round Robin | (по умолчанию) | Равнозначные серверы |
| Least Connections | least_conn | Разные по нагрузке запросы |
| IP Hash | ip_hash | Sticky sessions по IP |
| Hash | hash $request_uri | Кэш-консистентность |
Least Connections
upstream backend {
least_conn;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}
Healthcheck (Nginx Plus / nginx_upstream_check_module)
upstream backend {
server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
}
keepalive 32 в блоке upstream поддерживает постоянные соединения к бэкендам — снижает накладные расходы на TCP-хэндшейки.Реальные ошибки при балансировке нагрузки
Ошибка no live upstreams while connecting to upstream появляется, когда все серверы в блоке upstream помечены как недоступные — Nginx исчерпал лимит max_fails попыток к каждому из них и не может выбрать бэкенд для запроса.
2026/09/12 10:14:02 [error] 1421#1421: *88291 no live upstreams while connecting to upstream, client: 5.44.12.9, server: example.com, request: "GET /api/status HTTP/1.1", upstream: "http://backend"
Сначала проверьте, что бэкенды реально отвечают: curl -I http://10.0.0.1:8080 прямо с сервера Nginx. Если они живы, но Nginx всё равно считает их мёртвыми — уменьшите fail_timeout или увеличьте max_fails, потому что сервер помечается недоступным на весь период fail_timeout после превышения лимита ошибок.
Ошибка upstream sent too big header while reading response header from upstream означает, что бэкенд вернул заголовки ответа больше буфера, который Nginx выделил под них по умолчанию.
[error] 1421#1421: *91002 upstream sent too big header while reading response header from upstream, client: 91.200.10.4, server: example.com, upstream: "http://10.0.0.2:8080/"
Решение — увеличить proxy_buffer_size и proxy_buffers в блоке location, а не в upstream: они управляют буферизацией ответа проксируемого сервера, а не выбором бэкенда.
Sticky sessions: способы и ограничения
Балансировщик без учёта состояния хорош для stateless-бэкендов, но если приложение хранит сессию в памяти процесса, а не в общем хранилище вроде Redis, запросы одного пользователя обязаны попадать на один и тот же сервер.
| Способ | Как работает | Ограничение |
|---|---|---|
| ip_hash | Хэш по IP клиента | Ломается за общим NAT — много пользователей с одним IP |
| hash $cookie_jsessionid | Хэш по значению cookie | Требует, чтобы cookie уже существовала до первого запроса |
| sticky cookie (Nginx Plus) | Nginx сам ставит cookie с id бэкенда | Недоступно в open-source версии Nginx |
Для большинства проектов на open-source Nginx практичнее вынести сессии в общее хранилище и оставить least_conn без привязки к серверу — тогда выход одного бэкенда из строя не роняет сессии его пользователей.
Когда Nginx-балансировка не подходит
- Нужен балансировщик на уровне TCP/UDP для не-HTTP трафика — тогда используется блок
stream, а неhttp, с другим набором директив. - Требуется автоматическое масштабирование бэкендов без правки конфига вручную — open-source Nginx не умеет service discovery, нужен Consul-template, Kubernetes Ingress или Nginx Plus с API.
- Нужна балансировка между дата-центрами с учётом задержки сети — это задача для GeoDNS или Anycast, а не для upstream-блока на одном сервере.
- Единственный Nginx-балансировщик сам становится точкой отказа — для отказоустойчивости нужны минимум два узла с keepalived и общим VIP.
- Бэкенды требуют TLS-терминации с клиентскими сертификатами (mTLS) на каждом узле отдельно — проще завершать TLS один раз на балансировщике и пускать до бэкендов обычный HTTP внутри приватной сети.
Проверка результата
- Проверьте синтаксис конфигурации перед перезапуском:
nginx -tдолжен вернутьsyntax is okиtest is successful. - Примените конфиг без разрыва активных соединений:
systemctl reload nginx. - Убедитесь, что запросы реально распределяются: несколько раз выполните
curl http://yourdomain.com/и сверьте, какой бэкенд ответил. - Проверьте отказоустойчивость: остановите один бэкенд и убедитесь, что запросы продолжают обрабатываться остальными без ошибок 502 на стороне клиента.
Разбор кодов 502 и 504 от бэкендов — в статье про диагностику 502 и 504 в Nginx. Ограничение частоты запросов к каждому бэкенду настраивается через limit_req и limit_conn.
Частые вопросы
Что означает ошибка no live upstreams while connecting to upstream и как её устранить?
Она означает, что все серверы в блоке upstream помечены недоступными — лимит попыток max_fails исчерпан для каждого из них. Сначала проверьте бэкенды напрямую curl прямо с сервера Nginx: если они живы, уменьшите fail_timeout или увеличьте max_fails, потому что сервер остаётся помеченным недоступным весь этот период после превышения лимита ошибок.
Почему sticky sessions по ip_hash работают нестабильно для пользователей из одного офиса?
Пользователи за общим NAT выходят в интернет с одним и тем же внешним IP-адресом, и ip_hash направляет их всех на один и тот же бэкенд — при его перегрузке или падении страдает сразу вся группа. Надёжнее вынести хранение сессии в общее хранилище вроде Redis и балансировать без привязки к конкретному серверу.
Как добавить новый сервер в пул балансировки без остановки обслуживания текущих запросов?
Добавьте строку server с адресом нового бэкенда в блок upstream и примените конфигурацию командой systemctl reload — активные соединения при этом не разрываются, в отличие от полного перезапуска службы. Перед включением в общий пул стоит проверить новый сервер отдельным curl-запросом напрямую по его адресу.
Балансировщик Nginx сам может стать точкой отказа — как от этого защититься?
Да, единственный узел с Nginx — это единая точка отказа независимо от числа бэкендов за ним. Для отказоустойчивости нужны минимум два узла балансировки с keepalived и общим виртуальным IP-адресом, который переключается на живой узел автоматически при падении основного. Один балансировщик без резерва такую гарантию дать не может.