Балансировка нагрузки HTTP

  • Михаил
  • 12 мин. на прочтение
  • 69
  • 30 Jun 2022
  • 30 Jun 2022

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

 

Обзор

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

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

NGINX и NGINX Plus можно использовать в различных сценариях развертывания в качестве очень эффективного балансировщика нагрузки HTTP .

 

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

Чтобы начать использовать NGINX Plus или NGINX с открытым исходным кодом для балансировки нагрузки HTTP-трафика на группу серверов, сначала необходимо определить группу с помощью upstreamдирективы. Директива помещается в httpконтекст.

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

http {
    upstream backend {
        server backend1.example.com weight=5;
        server backend2.example.com;
        server 192.0.0.1 backup;
    }
}

Для передачи запросов группе серверов имя группы указывается в директиве ( proxy_passили директивах fastcgi_pass, memcached_pass, scgi_pass, или uwsgi_passдля этих протоколов). определено в предыдущем примере:

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

В следующем примере объединены два приведенных выше фрагмента и показано, как проксировать HTTP-запросы к группе внутренних серверов. Группа состоит из трех серверов, на двух из которых запущены экземпляры одного и того же приложения, а третий является сервером резервного копирования. Поскольку в блоке не указан алгоритм балансировки нагрузки upstream, NGINX использует алгоритм по умолчанию Round Robin:

http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server 192.0.0.1 backup;
    }
    
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}

 

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

NGINX Open Source поддерживает четыре метода балансировки нагрузки, а NGINX Plus добавляет еще два метода:

Round Robin — запросы распределяются равномерно по серверам с учетом веса серверов . Этот метод используется по умолчанию (нет директивы для его включения):

upstream backend {
   # no load balancing method is specified for Round Robin
   server backend1.example.com;
   server backend2.example.com;
}

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

upstream backend {
    least_conn;
    server backend1.example.com;
    server backend2.example.com;
}

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

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}

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

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
}

Универсальный хеш — сервер, на который отправляется запрос, определяется с помощью определяемого пользователем ключа, который может быть текстовой строкой, переменной или их комбинацией. Например, ключ может быть парным исходным IP-адресом и портом или URI, как в этом примере:

upstream backend {
    hash $request_uri consistent;
    server backend1.example.com;
    server backend2.example.com;
}

Дополнительный постоянный параметр hashдирективы включает балансировку нагрузки ketama с постоянным хэшем. Запросы равномерно распределяются по всем вышестоящим серверам на основе заданного пользователем значения хешированного ключа. Если вышестоящий сервер добавляется в вышестоящую группу или удаляется из нее, переназначаются только несколько ключей, что сводит к минимуму промахи в кэше в случае кэш-серверов с балансировкой нагрузки или других приложений, накапливающих состояние.

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

  • header– Время получения первого байта от сервера
  • last_byte– Время получения полного ответа от сервера
  • last_byte inflight– Время получения полного ответа от сервера с учетом незавершенных запросов

Случайный — каждый запрос будет передан на случайно выбранный сервер. Если twoпараметр указан, то сначала NGINX случайным образом выбирает два сервера с учетом весов серверов, а затем выбирает один из этих серверов указанным методом:

  • least_conn– Наименьшее количество активных подключений
  • least_time=header(NGINX Plus) — наименьшее среднее время получения заголовка ответа от сервера ( $upstream_header_time)
  • least_time=last_byte(NGINX Plus) — наименьшее среднее время получения полного ответа от сервера ( $upstream_response_time)

Примечание. При настройке любого метода, кроме Round Robin, поместите соответствующую директиву ( hash, ip_hash, least_conn, least_timeили random) над списком serverдиректив в upstream {}блоке.

 

Вес сервера

По умолчанию NGINX распределяет запросы между серверами в группе в соответствии с их весами, используя метод Round Robin. Параметр weightдирективы serverзадает вес сервера; по умолчанию 1:

upstream backend {
    server backend1.example.com weight=5;
    server backend2.example.com;
    server 192.0.0.1 backup;
}

В примере backend1.example.com имеет вес 5; два других сервера имеют вес по умолчанию ( 1), но тот, у которого есть IP-адрес 192.0.0.1, помечается как backupсервер и не получает запросы, если оба других сервера недоступны. При такой конфигурации весов все 6запросы 5отправляются на backend1.example.com и 1на backend2.example.com .

 

Медленный старт сервера

Функция медленного старта сервера предотвращает перегрузку недавно восстановленного сервера соединениями, что может привести к истечению времени ожидания и повторной пометке сервера как неисправного.

В NGINX Plus медленный запуск позволяет вышестоящему серверу постепенно восстанавливать свой вес 0до номинального значения после того, как он был восстановлен или стал доступным. Это можно сделать с помощью slow_startпараметра serverдирективы:

upstream backend {
    server backend1.example.com slow_start=30s;
    server backend2.example.com;
    server 192.0.0.1 backup;
}

Значение времени (здесь 30секунды) задает время, в течение которого NGINX Plus увеличивает количество подключений к серверу до полного значения.

Обратите внимание, что если в группе есть только один сервер max_fails, параметры директивы , fail_timeoutи игнорируются, и сервер никогда не считается недоступным.slow_startserver

 

Включение сохраняемости сеанса

Постоянство сеанса означает, что NGINX Plus идентифицирует сеансы пользователей и направляет все запросы в данном сеансе на один и тот же вышестоящий сервер.

NGINX Plus поддерживает три метода сохранения сеанса. Методы задаются stickyдирективой. (Для сохранения сеанса с NGINX с открытым исходным кодом используйте директиву hashor , как описано выше .)ip_hash

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

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    sticky cookie srv_id expires=1h domain=.example.com path=/;
}

В примере srv_idпараметр задает имя файла cookie. Необязательный expiresпараметр устанавливает время, в течение которого браузер сохраняет файл cookie (здесь 1час). Необязательный domainпараметр определяет домен, для которого устанавливается файл cookie, а необязательный pathпараметр определяет путь, для которого устанавливается файл cookie. Это самый простой метод сохранения сеанса.

Sticky route — NGINX Plus назначает «маршрут» клиенту при получении первого запроса. Все последующие запросы сравниваются с routeпараметром serverдирективы для идентификации сервера, на который проксируется запрос. Информация о маршруте берется либо из файла cookie, либо из URI запроса.

upstream backend {
    server backend1.example.com route=a;
    server backend2.example.com route=b;
    sticky route $route_cookie $route_uri;
}

Метод прилипчивого обучения — NGINX Plus сначала находит идентификаторы сеансов, проверяя запросы и ответы. Затем NGINX Plus «узнает», какой восходящий сервер соответствует какому идентификатору сеанса. Как правило, эти идентификаторы передаются в файле cookie HTTP. Если запрос содержит уже «выученный» идентификатор сеанса, NGINX Plus перенаправляет запрос на соответствующий сервер:

upstream backend {
   server backend1.example.com;
   server backend2.example.com;
   sticky learn
       create=$upstream_cookie_examplecookie
       lookup=$cookie_examplecookie
       zone=client_sessions:1m
       timeout=1h;
}

В примере один из вышестоящих серверов создает сеанс, устанавливая файл cookie EXAMPLECOOKIEв ответе.

Обязательный createпараметр задает переменную, указывающую, как создается новый сеанс. В этом примере новые сеансы создаются из файла cookie EXAMPLECOOKIE, отправленного вышестоящим сервером.

Обязательный lookupпараметр указывает, как искать существующие сеансы. В нашем примере существующие сеансы ищутся в файле cookie EXAMPLECOOKIE, отправленном клиентом.

Обязательный zoneпараметр указывает зону общей памяти, в которой хранится вся информация о закрепленных сессиях. В нашем примере зона называется client_sessions и имеет 1 размер в мегабайтах.

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

При наличии в кластере нескольких экземпляров NGINX, использующих метод «липкого обучения», возможна синхронизация содержимого их зон общей памяти при условии, что:

  • зоны имеют одинаковое имя
  • функциональность zone_syncнастраивается на каждом экземпляре
  • параметр syncуказан

 

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

В NGINX Plus можно ограничить количество активных подключений к вышестоящему серверу, указав максимальное количество с помощью max_connsпараметра.

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

upstream backend {
    server backend1.example.com max_conns=3;
    server backend2.example.com;
    queue 100 timeout=70;
}

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

Обратите внимание, что max_connsограничение игнорируется, если keepaliveв других worker processes. В результате общее количество подключений к серверу может превышать max_connsзначение в конфигурации, в которой память совместно используется несколькими рабочими процессами .

 

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

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

Инструкции по настройке проверки работоспособности для HTTP см. в разделе Проверки работоспособности HTTP.

 

Совместное использование данных с несколькими рабочими процессами

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

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

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

Например, если конфигурация группы не используется совместно, каждый рабочий процесс поддерживает собственный счетчик неудачных попыток передать запрос на сервер (устанавливается параметром max_fails ). В этом случае каждый запрос попадает только к одному рабочему процессу. Когда рабочий процесс, выбранный для обработки запроса, не может передать запрос на сервер, другие рабочие процессы ничего об этом не знают. В то время как некоторые рабочие процессы могут считать сервер недоступным, другие могут по-прежнему отправлять запросы на этот сервер. Чтобы сервер окончательно считался недоступным, количество неудачных попыток за время, заданное fail_timeoutпараметром, должно быть равно max_failsпроизведению на количество рабочих процессов. С другой стороны, zoneдиректива гарантирует ожидаемое поведение.

Точно так же метод балансировки нагрузки Least Connections может не работать должным образом без zoneдирективы, по крайней мере, при низкой нагрузке. Этот метод передает запрос на сервер с наименьшим количеством активных подключений. Если конфигурация группы не используется совместно, каждый рабочий процесс использует собственный счетчик количества подключений и может отправить запрос на тот же сервер, на который только что отправил запрос другой рабочий процесс. Однако вы можете увеличить количество запросов, чтобы уменьшить этот эффект. При высокой нагрузке запросы распределяются между рабочими процессами равномерно, и Least Connectionsметод работает как положено.

 

Установка размера зоны

Невозможно порекомендовать идеальный размер зоны памяти, поскольку модели использования сильно различаются. Требуемый объем памяти определяется тем, какие функции (такие как сохранение сеанса , проверки работоспособности или повторное разрешение DNS ) включены, а также тем, как идентифицируются вышестоящие серверы.

Например, при использовании sticky_routeметода сохранения сеанса и включенной одиночной проверки работоспособности зона размером 256 КБ может вместить информацию об указанном количестве вышестоящих серверов:

  • 128 серверов (каждый определяется как пара IP-адрес:порт)
  • 88 серверов (каждый определяется как пара имя хоста: порт, где имя хоста разрешается в один IP-адрес)
  • 12 серверов (каждый определяется как пара имя хоста: порт, где имя хоста разрешается в несколько IP-адресов)

 

Настройка балансировки нагрузки HTTP с использованием DNS

Конфигурацию группы серверов можно изменить во время выполнения с помощью DNS.

Для серверов в вышестоящей группе, которые идентифицируются доменным именем в serverдирективе, NGINX Plus может отслеживать изменения в списке IP-адресов в соответствующей записи DNS и автоматически применять изменения для балансировки нагрузки для вышестоящей группы, не требуя запустить снова. Это можно сделать, включив resolverдирективу в httpблок вместе с resolveпараметром к serverдирективе:

http {
    resolver 10.0.0.1 valid=300s ipv6=off;
    resolver_timeout 10s;
    server {
        location / {
            proxy_pass http://backend;
        }
    }
    upstream backend {
        zone backend 32k;
        least_conn;
        # ...
        server backend1.example.com resolve;
        server backend2.example.com resolve;
    }
}

В этом примере resolveпараметр serverдирективы указывает NGINX Plus периодически переопределять доменные имена backend1.example.com и backend2.example.com в IP-адреса.

Директива resolverопределяет IP-адрес DNS-сервера, на который NGINX Plus отправляет запросы (здесь 10.0.0.1). По умолчанию NGINX Plus повторно разрешает записи DNS с частотой, указанной временем жизни (TTL) в записи, но вы можете переопределить значение TTL с помощью validпараметра; в примере это 300секунды или 5минуты.

Необязательный ipv6=offпараметр означает, что для балансировки нагрузки используются только адреса IPv4, хотя по умолчанию поддерживается разрешение как адресов IPv4, так и IPv6.

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

 

Балансировка нагрузки серверов Microsoft Exchange

В NGINX Plus R7 и более поздних версиях NGINX Plus может проксировать трафик Microsoft Exchange на сервер или группу серверов и балансировать нагрузку.

Чтобы настроить балансировку нагрузки серверов Microsoft Exchange:

В locationблоке настройте проксирование к вышестоящей группе серверов Microsoft Exchange proxy_passдирективой:

location / {
    proxy_pass https://exchange;
    # ...
}

Чтобы соединения Microsoft Exchange проходили на вышестоящие серверы, в locationблоке установите proxy_http_versionзначение директивы в 1.1, а proxy_set_headerдирективу в Connection "", как и для keepalive-соединения:

location / {
    # ...
    proxy_http_version 1.1;
    proxy_set_header   Connection "";
    # ...
}

В httpблоке настройте вышестоящую группу серверов Microsoft Exchange с upstreamблоком с тем же именем, что и вышестоящая группа, указанная в proxy_passдирективе на шаге 1. Затем укажите ntlmдирективу, чтобы разрешить серверам в группе принимать запросы с проверкой подлинности NTLM:

http {
    # ...
    upstream exchange {
        zone exchange 64k;
        ntlm;
        # ...
    }
}

Добавьте серверы Microsoft Exchange в вышестоящую группу и при необходимости укажите метод балансировки нагрузки :

http {
    # ...
    upstream exchange {
        zone exchange 64k;
        ntlm;
        server exchange1.example.com;
        server exchange2.example.com;
        # ...
    }
}

 

Полный пример NTLM

http {
    # ...
    upstream exchange {
        zone exchange 64k;
        ntlm;
        server exchange1.example.com;
        server exchange2.example.com;
    }
    
    server {
        listen              443 ssl;
        ssl_certificate     /etc/nginx/ssl/company.com.crt;
        ssl_certificate_key /etc/nginx/ssl/company.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
       
        location / {
            proxy_pass         https://exchange;
            proxy_http_version 1.1;
            proxy_set_header   Connection "";
        }
    }
}

Дополнительные сведения о настройке Microsoft Exchange и NGINX Plus см . в руководстве по развертыванию балансировки нагрузки на серверы Microsoft Exchange с NGINX Plus .

 

Динамическая конфигурация с использованием API NGINX Plus

В NGINX Plus конфигурация группы вышестоящих серверов может динамически изменяться с помощью API NGINX Plus. Команду конфигурации можно использовать для просмотра всех серверов или определенного сервера в группе, изменения параметра для определенного сервера и добавления или удаления серверов. Дополнительные сведения и инструкции см. в разделе Настройка динамической балансировки нагрузки с помощью API NGINX Plus .