Статьи

Выбор техники балансировки нагрузки NGINX Plus

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

Ранее мы уже объясняли, как можно развернуть NGINX Plus  в центре обработки данных  (возможно, вместе с устаревшими контроллерами доставки приложений),  в контейнерах и в облачных средах, включая Amazon Web ServicesGoogle Cloud Platform и  Microsoft Azure .

В этом посте мы сосредоточимся на методах балансировки нагрузки (также называемых методами  или алгоритмами балансировки нагрузки  ) в NGINX Plus и NGINX, и предложим несколько советов о том, как выбрать правильный метод для различных вариантов использования. NGINX предоставляет четыре метода балансировки нагрузки ( Round RobinHashIP Hash и Least Connections ), а NGINX Plus добавляет еще один ( Least Time ). Все методы, кроме IP Hash, доступны как для TCP, так и для HTTP-трафика.

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

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

  • Балансировка нагрузки  в Руководстве администратора NGINX Plus содержит полный обзор.
  • Балансировка нагрузки приложений с помощью NGINX Plus  содержит подробные обсуждения расширенных функций в NGINX Plus, которые могут еще больше повысить эффективность метода распределения нагрузки.
  • Балансировка нагрузки с NGINX и NGINX Plus , часть 1  и  часть 2,  представляет собой пошаговое руководствокоторое превращает простой обратный прокси-сервер в комплексное решение для балансировки нагрузки с расширенными функциями NGINX Plus.
  • Страница «   Решения для балансировки нагрузки» содержит ссылки на блоги, вебинары и технические документы.

Для простоты мы сосредоточимся на балансировке нагрузки HTTP, которую вы настраиваете в  http контексте. Балансировка нагрузки TCP настраивается в  stream контексте. Хотя балансировщики нагрузки HTTP и TCP имеют паритет функций, доступные директивы и параметры несколько отличаются из-за внутренних различий между протоколами; подробности см. в документации о модулях Upstream для  HTTP  и  TCP .

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

  • server Блок определяет виртуальный сервер , который прослушивает трафик с характеристиками вы определяете, и доверенностями его к имени группы вышестоящих серверов. В наших примерах виртуальный сервер прослушивает порт по умолчанию (80) для HTTP-трафика, отправляемого на www.example.com , и передает  его в группу вышестоящих серверов, называемую  backend . Этот блок одинаков во всех наших примерах.
    server {
        server_name www.example.com;
    
        location / {
           proxy_pass http://backend;
        }
    }

    (NGINX Plus и NGINX может также балансировку нагрузки FastCGI, Memcached, SCGI и uwsgi внутренних серверов Replace.  proxy_pass С соответствующей директивой —  fastcgi_passmemcached_pass, scgi_passили  uwsgi_pass.)

  • В  upstream именах блоков выше по потоку группы и список серверов , которые принадлежат к нему, которые были определены по имени хоста, IP — адрес, или UNIX-домен пути сокета. В наших примерах вышестоящая группа, называемая backend,  включает три сервера:  web1web2 и  web3 . В этом  upstream блоке вы указываете метод балансировки нагрузки, поэтому мы выделим его в следующих разделах. В качестве примера, вот блок для метода по умолчанию, Round Robin:
    upstream backend {
        server web1;
        server web2;
        server web3;
    }

По-круговой

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

Учитывая приведенный ниже пример конфигурации  исходной  группы бэкэнда , подсистема балансировки нагрузки отправляет первые три запроса на соединение  по порядку в  web1web2 и  web3 , четвертый в  web1 , пятый в  web2 и т. Д.

upstream backend {
    server web1;
    server web2;
    server web3;
}

server {
    server_name www.example.com;

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

гашиш

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

В следующем примере  hash директива использует схему ( http  или  https ) и полный URL-адрес запроса в качестве основы для хэша:

upstream backend {
    hash $scheme$request_uri;

    server web1;
    server web2;
    server web3;
}

server {
    server_name www.example.com;

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

IP Hash

IP-хэш (доступен только для HTTP) — это предопределенный вариант метода Hash, в котором хэш основан на IP-адресе клиента. Вы устанавливаете это с  ip_hash директивой.

upstream backend {
    ip_hash;

    server web1;
    server web2;
    server web3;
}

server {
    server_name www.example.com;

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

Если у клиента есть адрес IPv6, хэш основывается на полном адресе. Если у него есть адрес IPv4, хеш основывается только на первых трех октетах адреса. Это разработано для оптимизации для интернет-клиентов, которым динамически назначаются IP-адреса из диапазона подсети (/ 24). В случае перезагрузки или переподключения, адрес клиента часто меняется на другой адрес в диапазоне сети / 24, но соединение по-прежнему представляет собой того же клиента, поэтому нет причины менять сопоставление с сервером.

Однако, если большая часть трафика на ваш сайт поступает от клиентов в одной сети / 24, IP-хэш не имеет смысла, поскольку он сопоставляет их все на одном сервере. В этом случае (или если вы хотите хешировать все четыре октета по другой причине), используйте метод Hash с  $remote_addr переменной вместо IP Hash.

hash $remote_addr;

Наименее Связи

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

upstream backend {
    least_conn;

    server web1;
    server web2;
    server web3;
}

server {
    server_name www.example.com;

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

Наименьшее время

Для метода наименьшего времени (доступно только в NGINX Plus) балансировщик нагрузки математически объединяет две метрики для каждого сервера — текущее количество активных соединений и средневзвешенное время ответа для прошлых запросов — и отправляет запрос на сервер с наименьшим стоимость.

Выбор параметра в  least_time директиве определяет, какое из двух времен ответа отслеживается: либо время получения заголовка ответа ( header), либо время получения полного ответа ( last_byte).

upstream backend {
    least_time (header | last_byte);

    server web1;
    server web2;
    server web3;
}

server {
    server_name www.example.com;

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

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

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

Модели трафика настолько различаются от сайта к сайту — и даже в пределах одного сайта в разное время дня — что не имеет смысла основывать выбор метода балансировки нагрузки на одной характеристике (например, интенсивный трафик и постоянный, недолговечные связи против долгожителей и т. д.). Тем не менее, мы рассмотрим плюсы и минусы каждого метода, чтобы помочь вам сузить диапазон вариантов для рассмотрения.

Выполнение тестов для сравнения методов

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

 Инструменты управления производительностью приложений очень удобны для такого типа тестирования — вы можете создавать собственные экраны с графиками для каждого из серверов в вышестоящей группе, что позволяет сравнивать их в реальном времени при изменении значений во время теста. Несколько APM предлагают собственные плагины для NGINX Plus и NGINX, включая  AppDynamicsDatadogDynatrace и  New Relic .

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

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

  • Загрузка процессора и памяти. Посмотрите на процент использования общей емкости как для процессора, так и для памяти. Если не все серверы загружены одинаково, трафик распределяется неэффективно.
  • Время отклика сервера — если время для одних серверов постоянно больше, чем для других, то каким-то образом «более тяжелые» запросы (требующие больших вычислений или обращений к базе данных или другим службам) перенаправляются на них несбалансированным образом. Попробуйте отрегулировать веса, потому что их отсутствие может вызвать дисбаланс, а не проблему с техникой балансировки нагрузки.
  • Общее время ответа клиенту. Опять же, для некоторых серверов постоянно увеличивается время, которое позволяет предположить, что они получают непропорционально большую долю отнимающих много времени запросов. И снова, вы можете попробовать настроить вес, чтобы увидеть, если это устраняет проблему.
  • Ошибки и неудачные запросы. Необходимо убедиться, что количество неудачных запросов и других ошибок не превышает обычного для вашего сайта, в противном случае вы тестируете условия ошибок вместо реалистичного трафика. Для некоторых ошибок (таких как код ответа HTTP  404 Not Found) время ответа может быть намного быстрее, чем если бы сервер должен был получить запрошенный файл; с помощью алгоритмов балансировки нагрузки Least Connections и Least Time это может привести к тому, что балансировщик нагрузки выберет сервер, который на самом деле не работает должным образом.

Плюсы, минусы и варианты использования

Итак, теперь давайте рассмотрим преимущества и недостатки каждого метода распределения нагрузки и опишем некоторые варианты использования, для которых они особенно подходят. Мы обсудим их в порядке повышения пригодности для большинства случаев использования. В качестве быстрого предварительного просмотра: мы считаем, что Least Connections (а для NGINX Plus и Least Time) — лучший выбор для самого широкого диапазона вариантов использования.

Хеш и IP Хеш

Методы балансировки нагрузки Hash и IP Hash создают фиксированную связь между клиентским запросом данного типа (записанным в хэш-значении) и определенным сервером. Вы можете распознать это как постоянство сеанса — все запросы с данным значением хеша всегда отправляются на один и тот же сервер.

Самый большой недостаток этих методов заключается в том, что они не гарантируют равномерное распределение запросов по серверам, не говоря уже о равномерной балансировке нагрузки. Алгоритм хэширования равномерно делит набор всех возможных значений хеш-функции на «сегменты», по одному на сервер в группе восходящего потока, но нет никакого способа предсказать, будут ли фактически выполняемые запросы иметь хэши, которые будут равномерно распределены. Предположим, например, что десять клиентов получают доступ к сайту, и алгоритм хеширования IP связывает хеш для семи IP-адресов с  web1 , один с  web2 , а два с  web3 . Сервер  web1  получает в два раза больше запросов, чем другие серверы вместе взятые.

Методы балансировки нагрузки Hash и IP Hash могут привести к неравномерному распределению нагрузки.

Поэтому имеет смысл использовать Hash или IP Hash, если польза от поддержки сеансов перевешивает возможные негативные последствия несбалансированной нагрузки. Это единственная форма сохранения сеанса в NGINX. NGINX Plus предоставляет три других   механизма сохранения сеанса, которые являются более сложными и работают в сочетании с фактической балансировкой нагрузки (вы настраиваете их с помощью  sticky директивы). Но вы можете выбрать Hash или IP Hash даже с NGINX Plus, потому что эти три механизма не работают в следующих случаях:

  • Приложение браузера или клиента не принимает файлы cookie, и приложение не может работать с механизмами сохранения сеанса без файлов cookie. Используйте метод IP-хеша, чтобы связать каждого клиента (в частности, его IP-адрес) с конкретным сервером.
  • Вы хотите каждый раз отправлять запросы на данный URL на один и тот же сервер, чтобы воспользоваться преимуществами кэширования на самом сервере. Используйте метод Hash с  $request_uri переменной, чтобы каждый раз получать файл с одного и того же сервера. Например, предположим, что вы знаете, что для обслуживания определенного   файла .php требуется несколько трудоемких обращений к базе данных, но извлеченные данные изменяются не часто и поэтому кэшируются. Если вы перенаправляете все запросы на файл на один и тот же сервер, только первый клиент испытывает длительную задержку из-за вызовов базы данных. Для всех последующих клиентов данные быстро извлекаются из кэша. Другое преимущество состоит в том, что только один сервер должен кэшировать этот конкретный набор данных. Поскольку вы не заканчиваете кеширование одинаковых данных на каждом сервере, вы можете использовать меньшие кеши.

Есть несколько случаев, когда хэш IP — и хэш, когда IP-адрес клиента находится в ключе — не работают:

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

Хеши являются детерминированными (алгоритм хеширования каждый раз дает одинаковые результаты). Это имеет пару положительных побочных эффектов: все экземпляры NGINX Plus или NGINX в запросах на балансировку нагрузки развертывания выполняются одинаковым образом, и сопоставление между хешем и сервером сохраняется при перезапусках балансировщика нагрузки. (Это фактически пересчитывается после перезапуска, но, поскольку результат всегда один и тот же, он эффективно сохраняется.)

On the other hand, changing the set of upstream servers usually forces recalculation of at least some of the mappings, breaking session persistence. You can reduce the number of recalculated mappings somewhat:

  • For the Hash method, include the consistent parameter to the hash directive; NGINX Plus uses theketama hashing algorithm, which results in less remapping.
  • For the IP Hash method, when you remove a server from the upstream group temporarily, add thedown parameter to its server directive, as for web2 in the following example. The mappings are not recalculated, on the assumption that the server will return to service soon.
    upstream backend {
        ip_hash;
    
        server web1;
        server web2 down;
        server web3;
    }

Round Robin

As noted previously, Round Robin is the default load-balancing method in NGINX Plus and NGINX. That certainly makes it the easiest method to choose – you don’t have to configure anything beyond the upstream group itself.

The general consensus is that Round Robin works best when the characteristics of the servers and requests are unlikely to cause some servers to become overloaded relative to others. Some of the conditions are:

  • All the servers have about the same capacity. This requirement is less important if differences between servers are accurately represented by server weights.
  • All the servers host the same content.
  • Requests are pretty similar in the amount of time or processing power they require. If there’s a wide variation in request weight, a server can become overloaded because the load balancer happens to send it a lot of heavyweight requests in quick succession.
  • Traffic volume is not heavy enough to push servers to near full capacity very often. If servers are already heavily loaded, it’s more likely that Round Robin’s rote distribution of requests will lead to push some servers “over the edge” into overload as described in the previous bullet.

Testing scenarios are particularly good use cases for Round Robin, because this method ensures that requests are distributed across all servers and in equal numbers (or the appropriately weighted proportion). Some other methods don’t always distribute traffic evenly when volume is low, which can skew test results.

The even nature of the distribution can also reveal whether caches are working at full capacity: because there’s no mechanism for sending repeated requests for a popular file to the same server, every server is likely to end up serving and caching a wide range of files (and, in many cases, many of the same files), which makes the cache more likely to fill.
Finally, the even initial distribution helps uncover issues with session persistence in NGINX Plus (as configured with the sticky directive).

Least Connections and Least Time

As we mentioned above, Least Connections is the most suitable load-balancing technique for the widest range of use cases, and particularly for production traffic. This is supported by anecdotal evidence from our customers. Its performance is stable and predictable.

Least Connections also effectively distributes workload across servers according to their capacity. A more powerful server fulfills requests more quickly, so at any given moment it’s likely to have a smaller number of connections still being processed (or even waiting for processing to start) than a server with less capacity. Least Connections sends each request to the server with the smallest number of current connections, and so is more likely to send requests to powerful servers. (Setting weights still results in even more efficient distribution of requests, however, as described in Setting Weights When Servers Aren’t Identical below).

You can consider Least Time (NGINX Plus only) a more sensitive version of Least Connections. By including the average response time, it takes into account the server’s recent performance history (it’s actually an exponentially weighted moving average, so older response times influence the average less than more recent response times).

Least Time is particularly suitable when the upstream servers have very different average response times. If, for example, you have servers in different data centers for purposes of disaster recovery, Least Time tends to send more requests to the local servers because they respond faster. Another use case is cloud environments, where server performance is often very unpredictable.

Наименьшее время является одним из методов балансировки нагрузки в NGINX Plus

Setting Weights When Servers Aren’t Identical

We’ve mentioned several times the importance of setting server weights when the servers in the upstream group have different capacities. It’s particularly important for the Round Robin load balancer, which otherwise sends the same number of requests to each server. That’s likely to result in a less powerful server being overloaded while a more powerful one sits partly idle.

To set weights, include the weight parameter on one or more server directives in the upstream block. The default value is 1.

You can think about the effect of setting weights for the different load-balancing techniques in the following way. Keep in mind that the descriptions are conceptually correct, but the implementation in the NGINX Plus code doesn’t necessarily use the indicated mathematical operations. Here’s the upstream group for our examples:

upstream backend {
    server web1 weight=6;
    server web2 weight=3;
    server web3;
}
  • Round Robin – Each server gets a percentage of the incoming requests that’s equal to its weight divided by the sum of the weights. In our example, out of every ten requests web1 gets six (60%),web2 gets three (30%), and web3 gets one (10%).
  • Hash and IP Hash – Recall that without weights the hashing algorithm evenly divides the set of all possible hash values into “buckets,” one per server in the upstream group. With weights, it instead sums the weights, divides the set of possible hashes among that number of buckets, and associates each server with the number of buckets equivalent to its weight. In our example, there are ten buckets, each with 10% of the possible hashes in it. Six buckets (60% of the possible hashes) are associated with web1, three buckets (30%) with web2, and one bucket (10%) with web3.
  • Least Connections and Least Time – We mentioned previously that even without weights the algorithms are pretty effective at distributing workload across servers according to their capacity. Setting weights improves their performance in this regard even more. Recall that Least Connections and Least Time send each request to the server with the lowest “score” (number of connections, or a mathematical combination of connections and time, respectively). When you assign weights, the load balancer divides each server’s score by its weight, and again sends the request to the server with the lowest value. Here’s an example for Least Connections with our sample weights and the indicated number of active connections: web1‘s score of 100 is lowest and it gets the request even though its connection count of 600 is 1.5 times web2‘s and more than 4 times web3‘s.
    • web1 – 600 active connections ÷ 6 = 100
    • web2 – 400 active connections ÷ 3 = 133
    • web3 – 125 active connections ÷ 1 = 125

Summary

After reviewing the pros and cons of the load-balancing techniques available in NGINX Plus and NGINX, we consider Least Connections (and, for NGINX Plus, Least Time) to be most suitable for the widest range of use cases. But it’s important for you to test several methods in your deployment, because its unique combination of traffic and server characteristics might make another method better for you.

We’d love to hear about your experiences with load balancing in different use cases. Please add them to the comments section below.

This article was written by Tony Mauro