Иногда возникают ситуации, когда требуется горизонтальное масштабирование определенных частей приложения. В таких случаях для распределения запросов между серверами требуется настройка балансировщика нагрузки – как раз об этом функционале Nginx мы и поговорим в данной статье.
Установка Nginx
Nginx доступен для установки пакетными менеджерами большинства дистрибутивов.
Ubuntu/Debian
Для установки на дистрибутивах, основанных на Debian, используйте команды:
sudo apt update
sudo apt install nginx
CentOS/Fedora/AlmaLinux/Rocky Linux
Для дистрибутивов семейства RHEL воспользуйтесь следующей командой для установки Nginx:
sudo dnf install nginx
По умолчанию сервис nginx не запускается после установки, для его запуска используйте команду:
sudo systemctl enable --now nginx
Конфигурация балансировщика Nginx
Настройка балансировки производится в блоке upstream
и выглядит следующим образом:
upstream name {
<method>;
server dest1 <options>;
server dest2 <options>;
...
server destN <options>;
}
В контексте upstream для настройки доступно указание метода балансировки (<method>
в примере кода выше):
round-robin
– метод по умолчанию, при использовании которого запросы распределяются по очереди;least-connected
– при использовании данного метода следующий запрос отправляется серверу с наименьшим количеством активных подключений;ip-hash
– сервер для обработки запроса выбирается на основе результата работы хэширующей функции с использованием IP-адреса клиента.
А также параметры сервера (<options>
в примере кода выше):
weight
– задает “вес” сервера, позволяя управлять частотой выбора определенного сервера. Значение по умолчанию равно 1. К примеру, в конфигурации
server dest1 weight=6;
server dest2 weight=3;
server dest3;
при обработке каждых 10 запросов они будут распределяться так: 6 запросов уйдут к dest1, 3 – к dest2 и один к dest3.
max_fails
– задает лимит неудачных попыток подключения к серверу за временной промежутокfail_timeout
перед тем, как пометить его недоступным. Значение по умолчанию 1, для отключения проверки установите значение 0.fail_timeout
– время, за которое при достижении заданных вmax_fails
неудачных попыток сервер помечается как недоступный. Через этот же промежуток времени nginx начнет пытаться повторно отправлять запросы к серверу.
После настройки апстрима его необходимо добавить в качестве адреса реверс-прокси, например:
http {
upstream myapp1 {
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://myapp1;
}
}
}
Nginx поддерживает балансировку трафика для HTTP, HTTPS, FastCGI, uwsgi, SCGI, memcached и gRPC. Для проксирования HTTPS достаточно указать “https” в качестве протокола в директиве proxy_pass
:
location / {
proxy_pass https://myapp1;
}
В случае настройки проксирования для других протоколов вместо proxy_pass
следует указывать соответствующие директивы:
- fastcgi_pass для FastCGI;
- uwsgi_pass для uwsgi;
- scgi_pass для SCGI;
- memcached_pass для memcached;
- grpc_pass для gRPC.
Пример конфигурации
В качестве примера использования балансировщика рассмотрим следующую ситуацию. Имеется основной сервер веб-приложения, а также отдельная облачная БД под него. Для nginx задана следующая конфигурация:
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
}
listen 80;
listen [::]:80;
server_name example.com;
server_tokens off;
}
server {
listen 443 ssl so_keepalive=on;
listen [::]:443 ssl so_keepalive=on;
http2 on;
server_name example.com;
server_tokens off;
ssl_certificate /etc/ssl/private/cf-origin-example.pem;
ssl_certificate_key /etc/ssl/private/cf-origin-example.key;
access_log /var/log/nginx/example_access.log;
error_log /var/log/nginx/example_error.log;
location / {
client_max_body_size 512M;
proxy_pass http://localhost:3000;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
В рамках масштабирования принимается решение добавить еще 2 VPS-сервера веб-приложения, для них подключается приватная сеть, адреса серверов:
10.16.0.1
10.16.0.2
Необходимо объединить эти серверы в одну группу с уже существующим бэкендом, а также настроить приоритет таким образом, чтобы при использовании балансировщика нагрузки серверов запросы преимущественно отправлялись на новые серверы. Для данного приложения не критично обращение к одному и тому же серверу, поэтому балансировка будет осуществляться, основываясь на количестве активных соединений.
Добавим в конфиг блок upstream
, указав в нем все адреса бэкенд-серверов:
upstream backend {
server 127.0.0.1:3000;
server 10.16.0.1:3000;
server 10.16.0.1:3000;
}
Зададим приоритет для новых серверов в два раза выше локального бэкенда, чтобы снизить нагрузку на основной сервер:
upstream backend {
server 127.0.0.1:3000;
server 10.16.0.1:3000 weight=2;
server 10.16.0.1:3000 weight=2;
}
Зададим параметры проверки состояния сервера – сервер будет помечаться недоступным, если за 30 секунд было 3 неудачных попытки подключения:
upstream backend {
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 10.16.0.1:3000 weight=2 max_fails=3 fail_timeout=30s;
server 10.16.0.1:3000 weight=2 max_fails=3 fail_timeout=30s;
}
Зададим выбранный нами ранее метод балансировки для балансировщика серверов:
upstream backend {
least_conn;
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 10.16.0.1:3000 weight=2 max_fails=3 fail_timeout=30s;
server 10.16.0.1:3000 weight=2 max_fails=3 fail_timeout=30s;
}
На этом конфигурация апстрима завершена, для его использования изменим адрес сервера в директиве proxy_pass
:
server {
...
location / {
...
proxy_pass http://backend;
...
}
}
Итоговая конфигурация выглядит следующим образом:
upstream backend {
least_conn;
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 10.16.0.1:3000 weight=2 max_fails=3 fail_timeout=30s;
server 10.16.0.1:3000 weight=2 max_fails=3 fail_timeout=30s;
}
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
}
listen 80;
listen [::]:80;
server_name example.com;
server_tokens off;
}
server {
listen 443 ssl so_keepalive=on;
listen [::]:443 ssl so_keepalive=on;
http2 on;
server_name example.com;
server_tokens off;
ssl_certificate /etc/ssl/private/cf-origin-example.pem;
ssl_certificate_key /etc/ssl/private/cf-origin-example.key;
access_log /var/log/nginx/example_access.log;
error_log /var/log/nginx/example_error.log;
location / {
client_max_body_size 512M;
proxy_pass http://backend;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
После изменения конфигурации в завершение настройки балансировщика нагрузки проверим конфиг на корректность:
sudo nginx -t
И в случае отсутствия ошибок перезагрузим конфигурацию nginx:
sudo nginx -s reload
На этом настройка балансировщика завершена и запросы будут отправляться на заданные в апстриме серверы.
Заключение
В данной статье мы рассмотрели, как установить Nginx и настроить его работу в качестве балансировщика. Также мы описали доступные методы балансировки и возможные настройки серверов в контексте балансировки трафика.
Если возникнут вопросы, напишите нам, пожалуйста, тикет из панели управления аккаунта (раздел “Помощь и поддержка”), а если вы захотите обсудить эту статью или облачные сервисы Бегета с коллегами по цеху – ждем вас в нашем сообществе в Telegram.