Что такое балансировка нагрузки?


Балансировка нагрузки подразумевает эффективное распределение входящего сетевого трафика между группой бэкенд-серверов. Задача же регулятора — распределить нагрузку между несколькими установленными бэкенд-серверами.

Существует несколько типов балансировщиков нагрузки:

  • Балансировщик нагрузки приложений.
  • Сетевой балансировщик нагрузки.
  • Балансировщик нагрузки шлюза.
  • Классический балансировщик нагрузки.

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

  1. Haproxy
  2. Nginx
  3. mod_athena
  4. Varnish
  5. Balance
  6. Linux Virtual Server (LVS)

В этой статье мы будем рассматривать Nginx.

Что такое балансировка нагрузки Nginx?


Nginx — это высокопроизводительный веб-сервер, который также может использоваться в качестве регулятора нагрузки — это процесс распределения веб-трафика между несколькими серверами с помощью Nginx.

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

Вы можете использовать либо Nginx open source, либо Nginx Plus для балансировки нагрузки HTTP-трафика на группу серверов.

Лично я использую Nginx open source для настройки своих стабилизаторов нагрузки, и именно его я собираюсь показать вам в этой статье.

Преимущества


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

Настраиваем Nginx


Установка Nginx


Первым шагом является установка Nginx. Он может быть установлен в Debian, Ubuntu или CentOS. Я собираюсь использовать Ubuntu, которую уже настроил на своём виртуальном сервере.

sudo apt-get update
sudo apt-get install nginx

Настройка Nginx в качестве балансировщика нагрузки


Создадим новый файл конфигурации для балансировщика нагрузки:

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

http {
   upstream app{
      server 10.2.0.100;
      server 10.2.0.101;
      server 10.2.0.102;
   }

   # Этот сервер принимает весь трафик на порт 80 и передает его вышестоящему потоку.
   # Обратите внимание, что имя вышестоящего потока и proxy_pass должны совпадать.

   server {
      listen 80;
      
      server_name mydomain.com;

      location / {
          include proxy_params;
          
          proxy_pass http://app;
          

          proxy_redirect off;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
      }
   }
}

В файле необходимо определить директиву upstream и server. Upstream определяет, куда Nginx будет передавать запросы после их получения. Она содержит IP-адреса группы серверов (бэкенда), на которые могут быть отправлены запросы в зависимости от выбранного метода регулирования нагрузки. По умолчанию Nginx использует метод балансировки round-robin для распределения мощности между серверами.

Сегмент server определяет порт 80, через который Nginx будет получать запросы. Он также содержит переменную proxy_pass.

Переменная proxy_pass используется для указания NGINX, куда отправлять получаемый трафик. В данном случае переменная proxy_pass указывает на 3 сервера. Это позволяет NGINX направлять получаемый трафик на любой из IP-адресов вышестоящих серверов. Nginx одновременно выступает в роли обратного прокси и балансировщика нагрузки.

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

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


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

Round Robin


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

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

Одно из ограничений заключается в том, что некоторые серверы будут простаивать просто потому, что они будут ждать своей очереди. В нашем примере, если A получит задание и выполнит его за секунду, это будет означать, что он будет простаивать до следующего задания. По умолчанию для распределения нагрузки между серверами Nginx использует именно метод round robin.

Round Robin с добавлением веса


Чтобы решить проблему простоя серверов, мы можем использовать server weights (серверные веса), чтобы указать Nginx, какие серверы должны иметь наибольший приоритет. Weighted Round Robin — один из самых популярных методов балансировки нагрузки, используемых сегодня.

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

Этот метод часто используется в сочетании с другими методами, такими как Session Persistence, для обеспечения равномерного распределения мощностей на все серверы. Сервер приложения с наибольшим параметром веса будет иметь приоритет (больше трафика) по сравнению с сервером с наименьшим числом (весом).

Для того чтобы включить весовые параметры сервера, нужно обновить конфигурацию Nginx:

http {
   upstream app{
      server 10.2.0.100 weight=5;
      server 10.2.0.101 weight=3;
      server 10.2.0.102 weight=1;
   }

  server {
      listen 80;

      location / {
          proxy_pass http://app;
      }
   }
}

Least Connection


Метод наименьшего числа соединений (Least Connection) — это популярная техника, используемая для равномерного распределения рабочей нагрузки между несколькими серверами. Метод работает путём маршрутизации каждого нового запроса на соединение — на сервер с наименьшим количеством активных соединений. Это гарантирует, что все серверы используются одинаково и ни один из них не перегружен.

http {
   upstream app{
      least_conn;
      server 10.2.0.100;
      server 10.2.0.101;
      server 10.2.0.102;
   }
   server {
      listen 80;

      location / {
          proxy_pass http://app;
      }
   }
}

Least Connection с добавлением веса


Данный метод используется для распределения рабочей нагрузки между несколькими вычислительными ресурсами (такими как серверы) с целью оптимизации производительности и минимизации времени отклика. Этот метод учитывает количество активных соединений на каждом сервере и присваивает соответствующие веса. Целью является распределение рабочей нагрузки таким образом, чтобы сбалансировать нагрузку и минимизировать время отклика.

http {
   upstream app{
      least_conn;
      server 10.2.0.100 weight=5;
      server 10.2.0.101 weight=4;
      server 10.2.0.102 weight=1;
   }
   server {
      listen 80;

      location / {
          proxy_pass http://app;
      }
   }
}

IP Hash


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

Это очень важный момент в случае развёртывания canary. Это позволяет нам, разработчикам, выпускать изменения для отдельной части пользователей, чтобы они могли всё протестировать и предоставить отзывы, прежде чем отправлять их в релиз.

Преимущество этого подхода в том, что он может обеспечить более высокую производительность, чем другие методы, такие как round-robin.

http {
   upstream app{
      ip_hash;
      server 10.2.0.100;
      server 10.2.0.101;
      server 10.2.0.102;
   }
   server {
      listen 80;

      location / {
          proxy_pass http://app;
      }
   }
}

URL Hash


Регулировка нагрузки URL Hash также использует алгоритм хэширования для определения того, какой сервер получит каждый из запросов на основе URL.

Он также похож на метод балансировки IP Hash, но разница в том, что мы хэшируем конкретные URL, а не IP. Это гарантирует, что все запросы равномерно распределяются между серверами, обеспечивая лучшую производительность и надёжность.

Перезапустите Nginx


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

sudo systemctl restart nginx

Проксирование HTTP-трафика на группу серверов


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

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

Прямой прокси защищает идентификационные данные клиентов, а обратный прокси защищает данные внутренних серверов.

Прямой прокси

Обратный прокси

Балансировка нагрузки с включённым HTTPS


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

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

Однако у него есть и ряд определённых проблем. Одна из них заключается в том, что для каждого запроса необходимо выполнить TLS-рукопожатие и поиск DNS, что может привести к задержке ответов.

Я предпочитаю, чтобы мои бэкенд-серверы приложений взаимодействовали с регулятором нагрузки по протоколу HTTP (SSL-терминация), а балансировщик нагрузки взаимодействовал с клиентами по протоколу HTTPS. Таким образом, при маршрутизации запросов к серверам приложений не нужно учитывать TLS-рукопожатия и поиск DNS.

Проверка работоспособности


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

Nginx может отслеживать здоровье наших HTTP-серверов в вышестоящей группе. Также он может выполнять пассивные проверки состояния и активные проверки состояния.

Пассивные проверки работоспособности


Nginx анализирует операции по мере их выполнения и пытается восстановить неудачные соединения для пассивной проверки работоспособности. Он идентифицирует сервер как недоступный и временно прекращает передачу запросов к нему, пока тот снова не будет признан активным, если операцию всё ещё невозможно возобновить.

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

failed_timeout задаёт время, в течение которого должно произойти определённое количество неудачных попыток, чтобы сервер был помечен как недоступный.

max_fails задаёт количество неудачных попыток.

upstream app{
      server 10.2.0.100 max_fails=3 fail_timeout=60s;
      server 10.2.0.101;
      server 10.2.0.102;
   }

Активные проверки здоровья


Nginx может периодически проверять здоровье вышестоящих серверов, отправляя специальные запросы на проверку здоровья каждому серверу и проверяя правильность ответа.

server {
    location / {
        proxy_pass http://app;
        health_check;
    }
}

К сожалению, я не использовал активные проверки здоровья, поскольку они, похоже, применимы только для Nginx Plus. Подробнее об активных проверках здоровья вы можете прочитать здесь.

Самоуправляемый балансировщик нагрузки в сравнении с управляемым сервисом


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

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

Ограничение количества соединений


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

Схожи ли обратный прокси и балансировщик нагрузки?
Да, обратный прокси и регулятор нагрузки во многом похожи. Они оба могут использоваться для повышения производительности и доступности веб-сайта или приложения, а также для распределения трафика между несколькими серверами.

Заключение


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

Спасибо за чтение!


НЛО прилетело и оставило здесь промокод для читателей нашего блога:

15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

Комментарии (14)


  1. Temoxa
    29.08.2022 12:16

    Подскажите состояние сессии пользователя при его повторных запросах будет идти к серверу, который был выбран балансировщиком при первом запросе?


    1. numb
      29.08.2022 12:52
      +1

      Для этого есть Nginx-sticky-module
      https://habr.com/ru/post/231523/


      1. Temoxa
        29.08.2022 18:55

        Спасибо


  1. AlexandreFrolov
    29.08.2022 12:39
    +1

    Спасибо за статью!

    Правильно ли я понимаю, что единой точкой отказа может быть сервер балансировки, на котором работает nginx? Как лучше обеспечить защиту от отказа этого сервера?

    И еще вопрос - как балансировщик на базе nginx будет поступать с отказавшими узлами бэкэнда? Он их автоматически исключит из процесса балансировки?


    1. pae174
      29.08.2022 13:03

      Можно сделать несколько балансировщиков и ротировать их уже через DNS roundrobin.

      Что бы DNS не стал бы единой точкой отказа можно использовать какого-либо провайдера, умеющего в anycast DNS.


      1. cupespresso
        30.08.2022 16:58

        Может знаете, что делать в такой ситуации.

        Есть локальный DNS-сервер (bind9 на Debian) с двумя A-записями, в которых два разных IP-адреса (разные подсети) ссылаются на один и тот же DNS-адрес. В идеальных условиях, с использованием roundrobin, на запрос по DNS-имени откликается один из двух веб-серверов с вероятностью 50/50. Но если один из серверов падает, то клиент через DNS-сервер может ещё долго стучаться на дохлый IP, пока не будет автоматически перенаправлен на рабочий сервер.

        Какими готовыми методами можно уменьшить время отклика до 5-10 секунд? На ум приходит разве что идея с написанием скрипта, проверяющего состояние веб-серверов и перезаписывающего А-записи в случае отсутствия отклика на запросы. Пробовал также keepalived, но как я понял, он идеально работает только с IP-адресами в одной подсети и не умеет спрашивать хосты по DNS-записям.


        1. pae174
          31.08.2022 19:16

          Если речь идет о том, что у вас два сервера являются зеркалами одного и того же сайта, то можно просто поставить всё под CloudFlare а там уже настроить два сервера, между которыми сам CloudFlare будет 50/50 раскидывать запросы. Фиксацию сессии CloudFlare в таком случае не делает. Управлять этим примитивным балансировщиком можно через API, оно там простое. Мониторить можно своим скриптом или с помощью Zabbix, у CloudFlare есть какая-то интеграция с Zabbix и он вроде бы должен видеть показатели по отдельным серверам (количество запросов, количество ответов/неответов и так далее). То есть должно в теории получить так, что Cloud Flare и предоставляет DNS, и проксирует трафик на два сервера, и выдает статистику, и принимает команды на исключение одного из этих серверов.

          При такой схеме балансировки конечный клиент (браузер) всегда работает с одним и тем же сервером и IP этого сервера для него никогда не меняется.

          Кроме того у CloudFlare есть полноценный платный балансировщик, который не требует никаких таких внешних скриптов для мониторинга и переключения.

          Если не хочется использовать CloudFlare или другие подобные системы тогда остается только собирать мониторинг и управление самостоятельно. Тогда да, это будет либо собственный скрипт, либо каке-то настройки Zabbix.


    1. YourChief
      29.08.2022 13:14

      Правильно ли я понимаю, что единой точкой отказа может быть сервер
      балансировки, на котором работает nginx? Как лучше обеспечить защиту от
      отказа этого сервера?

      Да. Есть вот такой простенький вариант как раз для такого случая: https://habr.com/ru/post/683770/

      И еще вопрос - как балансировщик на базе nginx будет поступать с
      отказавшими узлами бэкэнда? Он их автоматически исключит из процесса
      балансировки?

      Да: http://nginx.org/en/docs/http/load_balancing.html#nginx_load_balancing_health_checks. Впрочем, об этом и в статье написано.


  1. LuggerFormas
    29.08.2022 13:02
    +8

    Что-то уж совсем поверхностно. Таких статей как у дурака фантиков. Что-то посложней бы, с хэдером, примерами локаций, сложными кейсами


    1. Demacr
      29.08.2022 14:23

      Поддерживаю, а заодно бы и рассмотреть к примеру кластер из nginx'ов и их "готовку" вместе (хотелось бы посмотреть на практики и сравнить с тем, что сам городил).


    1. YourChief
      29.08.2022 14:32

      Да это практически один в один из документации: http://nginx.org/en/docs/http/load_balancing.html


  1. inkvizitor68sl
    29.08.2022 15:10

    Nginx справляется с балансировкой только до тех пор, пока все рилы живы или, хотя бы, быстро отвечают RST.

    И вообще не справляется, если одна из посещаемых ручек апстрима всегда возвращает ошибку.


  1. khe404
    30.08.2022 09:34

    На мой взгляд не раскрыт один из наиболее важных аспектов балансировки нагрузки. Причем это не вина автора это повсеместный подход. Практически ни в одной статье я не встречал пошагового описания процесса планирования и разработки структуры кластера.

    В детальной статье, в которой показано как установить и настроить NGINX ни слова не говорится о том в какой момент такая балансировка вообще становится актуальна. Что лучше балансировка в среде из 3 серверов по 1 ядру и 500 мб оперативки или прямой доступ на сервер с 3 ядрами и 1.5 Гб оперативки. Или балансировщик в среде с 1 сервером распределяющий запросы по изолированным виртуальным машинам и в каких случаях это вообще становится нужно. ( Может быть увеличить параметры виртуальной машины будет более правильным шагом ?) Ведь сам по себе NGINX уже балансирует запросы по набору запущенных в операционной системе процессов...

    Очень маловероятно, что набор из балансируемых серверов будет иметь совершенно независимые потребности во внесении и получении данных из базы данных, а значит сразу вопрос как сбалансировать потоки этих данных. На какие параметры запросов смотреть, может быть стоит балансировать не запросы пользователей, а обращения приложений к базе данных, а тут вопрос становится сильно далеким от настройки NGINX. И возникают проблемы репликации и синхронизации.

    Если у вас есть хорошие не очень сложные статьи по планированию самой балансировке, пожалуйста поделитесь.

    Спасибо.


  1. MagicWolf
    30.08.2022 18:36

    По идее nginx reload лучше nginx restart в случае, когда вы просто изменили конфиг.