Балансировка нагрузки в Nginx реализуется через директиву
Группа серверов объявляется директивой
Серверы с параметром
Если ни одна директива балансировки не указана, Nginx распределяет запросы циклически с учётом весов. В примере выше каждые 7 запросов распределятся так: 5 на
При ошибке обращения к серверу запрос передаётся следующему, и так до тех пор, пока не будут опробованы все работающие серверы. Если ни один не ответил успешно, клиенту возвращается результат последнего.
Запрос передаётся серверу с наименьшим числом активных соединений, с учётом весов. Если таких серверов несколько — между ними применяется round-robin.
Подходит, когда запросы сильно различаются по длительности обработки: короткие не будут ждать, пока освободится сервер, занятый длинным запросом.
Ключом хэширования служат первые три октета IPv4-адреса клиента или весь IPv6-адрес. Запросы одного клиента всегда попадают на один и тот же сервер. Если сервер становится недоступным, запросы перенаправляются на другой, но с высокой вероятностью это будет один и тот же сервер.
Если сервер нужно временно вывести из ротации без перераспределения хэшей, его помечают параметром
Позволяет задать произвольный ключ хэширования: текст, переменные или их комбинации.
Параметр
Без
Запрос передаётся серверу с наименьшим средним временем ответа и числом активных соединений. Параметр
Запрос передаётся случайно выбранному серверу с учётом весов. С параметром
Директива
Это пассивная проверка: Nginx не отправляет специальных health-check-запросов, а реагирует на реальные ошибки при обработке клиентских запросов. Активные периодические проверки (
По умолчанию Nginx открывает новое соединение к бэкенду на каждый запрос. Директива
Начиная с версии 1.29.7 кэш соединений задействован по умолчанию,
Для FastCGI-бэкендов дополнительно нужна директива
Дополнительные параметры пула (с версии 1.15.3):
Для привязки клиента к конкретному серверу на уровне HTTP-куки используется директива
Первый запрос клиента обрабатывается по обычному алгоритму балансировки, после чего в ответе устанавливается кука. Последующие запросы с этой кукой направляются на тот же сервер. Если сервер недоступен, выбирается новый.
Директива
С
Директива
Файл читается при парсинге конфигурации и обновляется при каждом изменении группы. Редактировать его вручную не рекомендуется.
Если в момент обработки запроса подходящий сервер не найден, запрос помещается в очередь. Директива
При переполнении очереди или истечении таймаута клиент получает ошибку 502.
Отсутствие
Удаление сервера из
Слишком большой
Ожидание активной проверки здоровья в open-source версии.
Перед применением изменений проверяйте синтаксис:
Для применения без остановки:
Убедиться, что балансировка работает, можно по логам доступа. Добавьте переменную
После нескольких запросов в логе будет видно, на какие бэкенды уходят запросы и как они распределяются.
Для диагностики на уровне соединений полезен
upstream, которая описывает группу бэкенд-серверов. Запросы распределяются между ними согласно выбранному алгоритму, а при отказе одного из серверов трафик автоматически перенаправляется на оставшиеся.Базовая структура upstream-блока
Группа серверов объявляется директивой
upstream в контексте http. Внутри перечисляются бэкенды с помощью директивы server. Адрес можно задать доменным именем, IP-адресом с необязательным портом или путём к UNIX-сокету с префиксом unix:. Если порт не указан, используется порт 80.
NGINX:
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
Серверы с параметром
backup получают трафик только тогда, когда все основные серверы недоступны. Доменное имя, которому соответствует несколько IP-адресов, автоматически раскладывается на несколько серверов.Алгоритмы балансировки
Round-robin (по умолчанию)
Если ни одна директива балансировки не указана, Nginx распределяет запросы циклически с учётом весов. В примере выше каждые 7 запросов распределятся так: 5 на
backend1.example.com, по одному на backend2.example.com:8080 и unix:/tmp/backend3.При ошибке обращения к серверу запрос передаётся следующему, и так до тех пор, пока не будут опробованы все работающие серверы. Если ни один не ответил успешно, клиенту возвращается результат последнего.
least_conn
Запрос передаётся серверу с наименьшим числом активных соединений, с учётом весов. Если таких серверов несколько — между ними применяется round-robin.
NGINX:
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
Подходит, когда запросы сильно различаются по длительности обработки: короткие не будут ждать, пока освободится сервер, занятый длинным запросом.
ip_hash
Ключом хэширования служат первые три октета IPv4-адреса клиента или весь IPv6-адрес. Запросы одного клиента всегда попадают на один и тот же сервер. Если сервер становится недоступным, запросы перенаправляются на другой, но с высокой вероятностью это будет один и тот же сервер.
NGINX:
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
Если сервер нужно временно вывести из ротации без перераспределения хэшей, его помечают параметром
down, а не удаляют из конфигурации.hash
Позволяет задать произвольный ключ хэширования: текст, переменные или их комбинации.
NGINX:
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
Параметр
consistent включает консистентное хэширование (алгоритм ketama). При добавлении или удалении сервера перераспределяется минимальное число ключей, что критично для кэширующих бэкендов: процент попаданий в кэш остаётся высоким.Без
consistent любое изменение состава группы приводит к перераспределению большинства ключей.least_time (коммерческая подписка)
Запрос передаётся серверу с наименьшим средним временем ответа и числом активных соединений. Параметр
header учитывает время получения заголовка ответа, last_byte — время получения всего ответа, inflight (с версии 1.11.6) — также незавершённые запросы.random (с версии 1.15.1)
Запрос передаётся случайно выбранному серверу с учётом весов. С параметром
two Nginx выбирает два случайных сервера, а затем применяет к ним указанный метод (по умолчанию least_conn).
NGINX:
upstream backend {
random two least_time=last_byte;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
Параметры доступности: max_fails и fail_timeout
Директива
server принимает два ключевых параметра, управляющих пассивной проверкой здоровья:| Параметр | Назначение | Значение по умолчанию |
|---|---|---|
max_fails | Число неудачных попыток за период fail_timeout, после которых сервер считается недоступным | 1 |
fail_timeout | Окно времени для подсчёта неудач и длительность, на которую сервер помечается недоступным | 10s |
NGINX:
upstream backend {
server backend1.example.com max_fails=3 fail_timeout=30s;
server backend2.example.com max_fails=3 fail_timeout=30s;
}
Это пассивная проверка: Nginx не отправляет специальных health-check-запросов, а реагирует на реальные ошибки при обработке клиентских запросов. Активные периодические проверки (
health_check) доступны только в коммерческой версии (Nginx Plus).Keepalive-соединения к бэкендам
По умолчанию Nginx открывает новое соединение к бэкенду на каждый запрос. Директива
keepalive внутри upstream включает пул постоянных соединений:
NGINX:
upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
Начиная с версии 1.29.7 кэш соединений задействован по умолчанию,
proxy_http_version уже равен 1.1 и заголовок Connection очищается автоматически. Для более ранних версий обе строки в location обязательны.Для FastCGI-бэкендов дополнительно нужна директива
fastcgi_keep_conn on:
NGINX:
upstream fastcgi_backend {
server 127.0.0.1:9000;
keepalive 8;
}
server {
location /fastcgi/ {
fastcgi_pass fastcgi_backend;
fastcgi_keep_conn on;
}
}
Дополнительные параметры пула (с версии 1.15.3):
keepalive_requests— максимальное число запросов по одному соединению до его закрытия. Слишком большое значение ведёт к росту потребления памяти.
keepalive_time(с 1.19.10) — максимальное время жизни соединения.
keepalive_timeout— таймаут неактивности, после которого соединение закрывается.
Sticky-сессии (коммерческая подписка)
Для привязки клиента к конкретному серверу на уровне HTTP-куки используется директива
sticky:
NGINX:
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
Первый запрос клиента обрабатывается по обычному алгоритму балансировки, после чего в ответе устанавливается кука. Последующие запросы с этой кукой направляются на тот же сервер. Если сервер недоступен, выбирается новый.
Динамическая переконфигурация (коммерческая подписка)
Директива
zone создаёт область разделяемой памяти для хранения конфигурации и состояния группы:
NGINX:
upstream dynamic {
zone upstream_dynamic 64k;
server backend1.example.com weight=5;
server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
server 192.0.2.1 max_fails=3;
server backend3.example.com resolve;
server backup1.example.com:8080 backup;
}
С
zone состав группы можно менять через API без перезагрузки Nginx. Параметр resolve требует директиву resolver в блоке http или upstream и позволяет автоматически обновлять адреса по DNS.Директива
state сохраняет текущий состав группы в файл, чтобы изменения пережили перезагрузку:
NGINX:
state /var/lib/nginx/state/servers.conf;
Файл читается при парсинге конфигурации и обновляется при каждом изменении группы. Редактировать его вручную не рекомендуется.
Очередь запросов (коммерческая подписка)
Если в момент обработки запроса подходящий сервер не найден, запрос помещается в очередь. Директива
queue задаёт максимальный размер очереди и таймаут:
NGINX:
upstream backend {
queue 100 timeout=30s;
server backend1.example.com;
server backend2.example.com;
}
При переполнении очереди или истечении таймаута клиент получает ошибку 502.
Типичные ошибки при настройке
Отсутствие
proxy_http_version 1.1 и очистки Connection при использовании keepalive (версии до 1.29.7). Без этих директив пул соединений не работает: каждый запрос открывает новое TCP-соединение.Удаление сервера из
ip_hash-группы вместо пометки down. Удаление меняет хэш-кольцо и перераспределяет клиентов. Параметр down сохраняет текущее распределение.Слишком большой
keepalive_requests. Соединения накапливают память; периодическое закрытие необходимо. Значение по умолчанию обычно достаточно.Ожидание активной проверки здоровья в open-source версии.
max_fails/fail_timeout — пассивная проверка. Если на бэкенд нет трафика, его недоступность не будет обнаружена. Для активных проверок нужен Nginx Plus или внешний health-checker.hash без consistent при частых изменениях состава группы. Каждое добавление или удаление сервера перераспределяет большинство ключей, что приводит к массовому промаху кэша.Проверка конфигурации и диагностика
Перед применением изменений проверяйте синтаксис:
Bash:
nginx -t
Для применения без остановки:
Bash:
nginx -s reload
Убедиться, что балансировка работает, можно по логам доступа. Добавьте переменную
$upstream_addr в формат лога:
NGINX:
log_format upstream_log '$remote_addr -> $upstream_addr [$time_local] '
'"$request" $status';
access_log /var/log/nginx/upstream.log upstream_log;
После нескольких запросов в логе будет видно, на какие бэкенды уходят запросы и как они распределяются.
Для диагностики на уровне соединений полезен
stub_status (open-source) или API-модуль (коммерческая версия), которые показывают текущие активные соединения и запросы.
