Как настроить балансировку нагрузки в Nginx
Практика3 минРедакция Innovialabs
Коротко
Опишите серверы приложения в блоке upstream, выберите метод (round-robin, least_conn, ip_hash или hash), задайте max_fails и fail_timeout и направьте туда proxy_pass — Nginx сам распределит запросы и уберёт упавший сервер.
Короткий ответ
Балансировка в Nginx строится из двух частей: блока upstream со списком серверов и директивы proxy_pass, которая отправляет туда запросы. Минимальная рабочая конфигурация:
upstream app_backend {
server 10.0.0.11:3000;
server 10.0.0.12:3000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_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;
}
}
По умолчанию запросы идут по кругу (round-robin). Дальше конфигурацию стоит доработать под вашу нагрузку.
Как выбрать метод балансировки
Метод указывается первой строкой внутри upstream.
| Метод | Как работает | Когда подходит |
|---|---|---|
| round-robin (по умолчанию) | По очереди, с учётом весов | Одинаковые серверы, короткие запросы |
least_conn | На сервер с наименьшим числом активных соединений | Запросы разной длительности, WebSocket, загрузки файлов |
ip_hash | Один IP клиента — один сервер | Простая «привязка» клиента без cookie |
hash $key consistent | Сервер выбирается по любому ключу | Привязка по cookie, URL или заголовку; кеши |
random two least_conn | Два случайных сервера, из них менее загруженный | Несколько балансировщиков перед одним пулом |
Для большинства веб-приложений разумный старт — least_conn.
Пассивные проверки здоровья
Бесплатная версия Nginx проверяет серверы пассивно: по результатам реальных запросов. Параметры задаются у каждого сервера:
upstream app_backend {
least_conn;
server 10.0.0.11:3000 max_fails=3 fail_timeout=30s;
server 10.0.0.12:3000 max_fails=3 fail_timeout=30s;
}
- max_fails — сколько неудачных попыток за период
fail_timeoutделает сервер «недоступным». - fail_timeout — и окно подсчёта ошибок, и время, на которое сервер исключается.
Что считать ошибкой, решает proxy_next_upstream. По умолчанию это ошибка соединения и таймаут. Можно добавить коды ответа:
proxy_next_upstream error timeout http_502 http_503;
proxy_next_upstream_tries 2;
Осторожно с неидемпотентными запросами: повтор POST на другой сервер может создать дубль заказа. Nginx по умолчанию не повторяет такие запросы, и включать non_idempotent стоит только осознанно. Активные проверки (health_check) есть только в коммерческой NGINX Plus; в бесплатной версии их заменяют внешним мониторингом.
Веса и резервные серверы
Если серверы разные по мощности, используйте weight:
upstream app_backend {
server 10.0.0.11:3000 weight=3;
server 10.0.0.12:3000 weight=1;
server 10.0.0.13:3000 backup;
server 10.0.0.14:3000 down;
}
weight=3— сервер получает примерно втрое больше запросов.backup— включается, только когда все основные серверы недоступны. Не работает вместе сhash,ip_hashиrandom.down— сервер временно выведен из ротации, удобно при обслуживании.
Sticky-сессии
Привязка пользователя к серверу нужна, если сессии хранятся в памяти приложения. В бесплатном Nginx есть два способа:
# по IP клиента
ip_hash;
# по cookie сессии
hash $cookie_sessionid consistent;
ip_hash плохо работает, когда много пользователей выходят в интернет через один IP (офис, мобильный оператор). Привязка по cookie точнее. Но лучший вариант — вообще отказаться от sticky-сессий и хранить сессии в Redis или базе: тогда любой сервер может обработать любой запрос, а масштабирование и обновления проходят проще.
Соединения с бэкендом
Чтобы не открывать новое TCP-соединение на каждый запрос, включите keepalive:
upstream app_backend {
least_conn;
server 10.0.0.11:3000;
server 10.0.0.12:3000;
keepalive 32;
}
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
Частые ошибки
- Забыли передать
HostиX-Forwarded-For— приложение видит неверный домен и IP балансировщика. max_fails=0— проверки отключены, запросы продолжают идти на упавший сервер.- Сессии в памяти без привязки — пользователя случайно «разлогинивает».
- Изменили конфиг и не проверили его: всегда запускайте
nginx -t, затемnginx -s reload.