Как настроить балансировку нагрузки на сервере при помощи Nginx

Иногда возникают ситуации, когда требуется горизонтальное масштабирование определенных частей приложения. В таких случаях для распределения запросов между серверами требуется настройка балансировщика нагрузки – как раз об этом функционале 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 следует указывать соответствующие директивы:

Пример конфигурации

В качестве примера использования балансировщика рассмотрим следующую ситуацию. Имеется основной сервер веб-приложения, а также отдельная облачная БД под него. Для 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.

5
252