Бесплатная миграция IT-инфраструктуры в облако

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

Дмитрий Бахтенков
Дмитрий Бахтенков
Технический писатель
30 июня 2023 г.
3690
10 минут чтения
Средний рейтинг статьи: 5

Немного теории

Современные приложения могут обрабатывать множество запросов одновременно, и при этом, даже при высокой нагрузке, они должны возвращать пользователям корректную информацию. Масштабировать приложения можно разными способами:

  • Вертикальное масштабирование -— просто «накинуть» оперативной памяти, мощностей процессора — арендовать или купить более мощный сервер. На ранних этапах развития приложения это просто, но у такого подхода есть недостатки — цена и ограничения современного железа.

Image9

  • Горизонтальное масштабирование — добавить больше инстансов приложения. Поднять второй сервер, развернуть на нём точно такое же приложение и каким-то образом распределять трафик между этими экземплярами приложений.

Image10

Горизонтальное масштабирование, с одной стороны, может быть дешевле и менее ограничивать нас в железе — можно просто добавить ещё инстансов приложения. Однако теперь нам необходимо распределять пользовательские запросы между разными экземплярами приложения. 

Балансировка нагрузки (load balancing) — это способ распределения запросов к приложению (сетевого трафика) между некоторым количеством устройств. 

Балансировщик нагрузки — это программа-посредник, которая располагается между пользователем и группой приложений. Общая логика следующая:

  1. Пользователь заходит на сайт по определенному домену, за которым скрывается IP-адрес балансировщика нагрузки. 
  2. Балансировщик на основе настроек определяет, на какой из экземпляров приложения перенаправлять трафик от пользователя.
  3. Пользователь получает ответ от нужного экземпляра приложения.

Image4

Какие проблемы решает балансировка нагрузки?

  • Повышение доступности приложения: Балансировщики нагрузки обладают функционалом для обнаружения аварийных ситуаций на серверах. В случае отказа одного из серверов балансировщик может автоматически перенаправить трафик на другой адрес, обеспечивая бесперебойную работу приложения для пользователей.
  • Масштабируемость: Одной из основных задач балансировщика является распределение нагрузки между экземплярами приложения. Это позволяет применять горизонтальное масштабирование, добавляя новые экземпляры приложения и увеличивая общую производительность системы.
  • Улучшение безопасности: Балансировщики нагрузки могут включать в себя функции, связанные с безопасностью. Они могут отслеживать трафик, фильтровать запросы, обеспечивать маршрутизацию через фаерволы и другие механизмы, что способствует повышению безопасности приложения.

Какие есть инструменты балансировки сетевого трафика?

Существует довольно много приложений, которые могут выступать в качестве балансировщика нагрузки, однако одним из самых популярных является Nginx. Его и рассмотрим в данной статье.

Nginx

Nginx — это универсальный веб-сервер. Он отличается хорошей производительностью, низким потреблением ресурсов и своими широкими возможностями. Nginx можно использовать как:

  • Веб-сервер
  • Реверс-прокси и балансировка нагрузки
  • Почтовый прокси-сервер
  • И многое другое.

На сайте можно узнать подробнее про возможности Nginx. Ну а мы перейдём к практике.

Установка Nginx на Ubuntu

Nginx можно установить на все популярные дистрибутивы Linux: Ubuntu, CentOS и другие. В статье мы будем использовать Ubuntu. Чтобы установить Nginx, используем следующие команды:

sudo apt update
sudo apt install nginx

Чтобы убедиться, что всё прошло успешно, можно использовать команду:

systemctl status nginx

Без Названия (1)

Файлы конфигураций для Nginx находятся в каталоге /etc/nginx/sites-available/. По умолчанию в этом каталоге создаётся файл default. В нём мы и будем писать нашу конфигурацию.

Пример настройки

начала откроем файл конфигурации по умолчанию:

cd /etc/nginx/sites-available/
sudo nano default

Поместим сюда следующую конфигурацию:

   upstream application{
      server 10.2.2.11; # ip-адреса серверов для распределения запросов между ними
      server 10.2.2.12;
      server 10.2.2.13;
   }

   server {
      listen 80; # по этому порту будет открываться nginx


      location / {
         # описываем, куда перенаправлять трафик от nginx
          proxy_pass http://application;
      }
   }

Для настройки балансировки нагрузки в Nginx в конфигурации нужно определить два блока:

  • upstream — определяет адреса серверов, между которыми будет распределяться сетевой трафик. Тут мы указываем IP-адреса, порты и, при необходимости, методы балансировки нагрузки. Их мы обсудим далее.
  • server — определяет способ, с помощью которого Nginx будет получать запросы. Обычно тут указывается порт, доменное имя и другие параметры.
  • Путь proxy_pass — описывает, куда эти запросы надо перенаправлять. Это название указанного выше upstream.

Таким образом, Nginx используется не только как балансировщик нагрузки, но ещё и как обратный прокси (reverse proxy). Реверс-прокси — это сервер, который располагается между клиентом и экземплярами приложений. Он перенаправляет запросы от клиентов в бэкенд, и при этом может обеспечивать нас дополнительными функциями, например, такими как SSL-сертификаты, логирование и др.

Методы балансировки нагрузки

Round Robin

Существует довольно много методов балансировки. Nginx по умолчанию использует алгоритм Round Robin. Он довольно прост. Допустим, у нас есть приложения 1, 2 и 3. Балансировщик нагрузки отправит первый запрос на первое приложение:

Image12

Затем на 2:

Image13

Затем на 3:

Image1

И далее снова на 1:

Image14

Рассмотрим на примере. Я развернул два приложения и настроил балансировку нагрузки с помощью Nginx для них.

upstream application {
   server 172.25.208.1:5002#first
   server 172.25.208.1:5001; #second
}

 Давайте посмотрим, как это работает на практике:

Image7

Первый запрос отправляет нас на первый сервер, второй запрос — на второй сервер, а затем снова на первый. Однако этот алгоритм имеет ограничение — экземпляры бэкенда будут простаивать просто потому, что ждут своей очереди.

Round Robin с указанием весов

Чтобы избежать простоя серверов, можно использовать некоторый числовой приоритет. У каждого сервера появляется свой вес, который определяет, как много трафика распределяется на конкретный экземпляр приложения. Таким образом мы гарантируем, что более мощные серверы получат больше трафика. 

В Nginx приоритет указывается с помощью server weights следующим образом:

upstream application{
      server 10.2.2.11 weight=5;
      server 10.2.2.12 weight=3;
      server 10.2.2.13 weight=1;
   }

При такой настройке сервер с адресом 10.2.2.11 получит наибольшее количество трафика, так как у него указан наибольший вес.

Такой подход более надёжен, чем обычный Round Robin, однако он всё ещё имеет недостаток — вручную мы можем указать вес, основываясь на мощности сервера, но при этом сами запросы также могут различаться по скорости выполнения: есть более долгие и тяжёлые, а есть быстрые и незатратные.

Рассмотрим этот метод на примере.

Настройка:

upstream application {
   server 172.25.208.1:5002 weight=3; #first
   server 172.25.208.1:5001 weight=1; #second
}

Результат:

Без Названия (2)

Как мы видим, теперь каждый четвёртый запрос отправляется на второй сервер.

Least Connection

Что, если отойти от Round Robin? Распределять запросы между серверами можно не просто по порядку, а, например, основываясь на каких-либо параметрах. Отлично подойдёт количество активных соединений с сервером.

Алгоритм Least Connection обеспечивает равномерное распределение нагрузки между экземплярами приложения, как раз основываясь на количестве соединений с сервером. Чтобы его настроить, в блоке upstream надо указать least_conn;:

upstream application{
      least_conn;
      server 10.2.2.11;
      …
  }

Вернёмся к нашему примеру.

Чтобы проверить работу этого алгоритма, я написал скрипт, который отсылает 500 запросов параллельно и смотрит, на какое из приложений попал каждый запрос. 

Вот вывод этого скрипта:

4487f407 1f7b 4981 Bbd8 D07a49b837e1

Кроме того, этот алгоритм может использоваться вместе с весами для адресов, по аналогии с Round Robin. В этом случае веса будут обозначать количество соединений с этим адресом по отношению к другим адресам — например, в случае с весами 1 и 5, на адрес с весом 5 попадёт в пять раз больше соединений, чем на адрес с весом 1.

Пример такой настройки:

upstream application{
      least_conn;
      server 10.2.2.11 weight=5;
      …
   }

А вот настройка для примера:

upstream loadbalancer {
   least_conn;
   
server 172.25.208.1:5002 weight=3; #first
  
 server 172.25.208.1:5001 weight=1; #second
}

И вывод скрипта:

Image6

Как мы видим, запросов на первый сервер ровно в три раза больше, чем на второй. 

IP Hash

Этот метод работает на основе IP-адреса клиента. Он гарантирует, что все запросы с одного адреса будут доставлены на один и тот же экземпляр приложения. Алгоритм работает следующим образом: высчитывает хэш у адреса клиента и адреса сервера, и использует этот результат как уникальный ключ при балансировке.

Такой подход может быть полезен при blue green deployment, когда мы по очереди обновляем версию каждого бэкэнда. Мы сможем направить все запросы на адрес бэкэнда со старой версией, затем обновить новый и направить часть пользователей на него. Если всё хорошо, можно направить всех пользователей уже на новую версию бэкэнда и обновить старую.

Пример настройки:

upstream app{
      ip_hash;
      server 10.2.2.11;
      …
   }

При такой настройке в нашем примере все запросы теперь уходят только на одно приложение:

Image2

Обработка ошибок

При настройке балансировщика также важно обнаруживать неполадки с серверами, и, в случае чего, прекращать направлять трафик на «упавшие» экземпляры приложения. 

Чтобы балансировщик мог пометить адрес сервера как недоступный, необходимо определить дополнительные параметры в блоке upstream: failed_timeout и max_fails.

  • failed_timeout — тут мы указываем время, в течение которого должно произойти определённое количество ошибок соединения, чтобы адрес из блока upstream стал помечен как недоступный.
  • max_fails — задаём это самое количество ошибок соединения.

Пример настройки:

upstream application{
      server 10.2.0.11 max_fails=2 fail_timeout=30s;
      …
 }

Рассмотрим пример на практике. Я «положу» один из тестовых бэкэндов и добавлю соответствующую настройку.

Image3

Первый экземпляр бэкэнда из примера теперь отключен.

Image15

Nginx перенаправляет трафик только на второй сервер.

Сравнительная таблица алгоритмов распределения трафика

Алгоритм

Плюсы

Минусы

Round Robin

  • Простой и легковесный алгоритм.
  • Равномерно распределяет нагрузку между приложениями.
  • Хорошо масштабируется.
  • Не учитывает разную производительность серверов.
  • Не учитывает текущую загрузку приложений.

Weighted Round Robin

  • Даёт возможность задавать различные веса для серверов, отражающие их производительность
  • Не учитывает текущую загрузку приложений.
  • Может потребоваться ручная настройка весов.

Least Connection

  • Распределяет нагрузку на приложения с наименьшим количеством активных соединений.
  • Может привести к неравномерному распределению нагрузки при большом количестве медленных клиентов.

Weighted Least Connection

  • Учитывает разную производительность серверов, опираясь на количество активных соединений.
  • Распределяет нагрузку пропорционально весам и количеству соединений.
  • Может потребоваться ручная настройка весов.

IP Hash

  • Привязывает клиента к определенному IP-адресу.
  • Обеспечивает сохранение состояния сеанса клиента на одном сервере.
  • Не учитывает текущую загрузку приложений.
  • Не смотрит на производительность серверов.
  • Может привести к неравномерному распределению нагрузки при большом количестве клиентов с одинаковым IP-адресом.

Заключение

В этой статье мы погрузились в тему load balancing. Узнали, какие существуют методы балансировки нагрузки в Nginx и разобрали их на примере. Эти примеры можно найти в моем профиле на Гитхабе.

Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
30 июня 2023 г.
3690
10 минут чтения
Средний рейтинг статьи: 5
Комментарии 2
Anton Plekhov
Anton Plekhov
13.12.2023, 04:18

Дмитрий, спасибо! Очень хорошо и интересно рассказано.

Подскажите пожалуйста, какую минимальную конфигурацию вы рекомендуете заложить на сервер, используемый для балансировки нагрузки? Можно ли совсем простенький использовать (2Гб памяти, 1 ядро) или надо что-то посущественнее?

Команда Timeweb Cloud
Команда Timeweb Cloud
14.12.2023, 03:19

Добрый день! Сам Nginx потребляет немного ресурсов. В целом всё зависит от планируемой нагрузки, количества узлов и т.д., но указанной конфигурации должно быть достаточно. Можно воспользоваться мониторингом сервера и самого Nginx и уже в процессе увеличивать ресурсы сервера балансировки, если это необходимо.