Перейти к содержанию

Балансировка нагрузки между инстансами uWSGI с помощью nginx

Конфиг

nginx-load-balancer.conf
##########################################################################################
#  Copyright 2024 Viacheslav Kolupaev; author's website address:
#
#   https://vkolupaev.com/
#
# Licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
# International License (the "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   https://creativecommons.org/licenses/by-nc-nd/4.0/
#
# Unless required by applicable law or agreed to in writing, the material distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
# OF ANY KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
##########################################################################################

##########################################################################################
# Nginx config file optimized for `rec-als` application.
#
# Payload compression is disabled because it is better to implement it in applications.
##########################################################################################

# Automatically selects the number of workers based on the number of processor cores.
worker_processes auto;

events {
    # This value can be increased depending on the workload.
    worker_connections 1024;
}

http {
    upstream inference_cluster {
        # Application instances (replicas).
        server inference1:<port>;
        server inference2:<port>;

        # Number of keepalive connections to each server in upstream.
        keepalive 20;
    }

    server {
        # The port on which Nginx will accept incoming requests.
        listen 8099;

        location / {
            # Nginx communicates with uWSGI using the uWSGI protocol rather than HTTP.
            # https://uwsgi-docs.readthedocs.io/en/latest/Nginx.html
            uwsgi_pass inference_cluster;
            include uwsgi_params;

            uwsgi_read_timeout 2s;
            uwsgi_send_timeout 2s;
            uwsgi_buffer_size 64k;
            uwsgi_buffers 4 64k;
            uwsgi_busy_buffers_size 128k;
            uwsgi_temp_file_write_size 128k;

            # Only affects the interaction between the client and Nginx,
            # not the interaction between Nginx and uWSGI.
            add_header Connection "Keep-Alive";

        }
    }
}

Опции

keepalive

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

При расчете значения keepalive следует учитывать следующие факторы:

  1. Число инстансов приложения: Значение должно быть больше числа инстансов приложения, чтобы nginx смог поддерживать соединения с каждым из этих инстансов.
  2. RPS (Requests Per Second): У вас примерно 100 RPS на инстанс. Это означает, что каждый инстанс обрабатывает 100 запросов в секунду.
  3. Длительность соединения: Если соединения поддерживаются в течение длительного времени, это может уменьшить количество новых соединений, которые необходимо устанавливать.
  4. Балансировка нагрузки: Если у вас равномерная балансировка нагрузки, вы можете распределить соединения между всеми инстансами.

Для расчета оптимального значения keepalive можно использовать следующее эмпирическое правило:

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

Пример расчета:

  • Среднее количество соединений на инстанс: 100 RPS / 10 инстансов = 10 соединений.
  • Установите keepalive на уровне, который немного превышает это значение, например, 15-25, чтобы учесть возможные пики нагрузки.

add_header Connection "Keep-Alive"

Включение директивы add_header Connection "Keep-Alive" в конфигурации nginx может иметь следующие последствия:

  1. Улучшение производительности: Использование заголовка Connection: Keep-Alive позволяет поддерживать соединение между клиентом и сервером открытым для нескольких запросов. Это снижает накладные расходы на установку нового TCP-соединения для каждого запроса, что может улучшить производительность и уменьшить задержки.
  2. Снижение нагрузки на сервер: Поддержание открытых соединений уменьшает количество новых соединений, которые сервер должен обрабатывать, что может снизить нагрузку на сервер, особенно при высоких нагрузках.
  3. Увеличение использования ресурсов: Хотя Keep-Alive может снизить нагрузку на установку соединений, он также может увеличить использование ресурсов, так как соединения остаются открытыми дольше. Это может привести к увеличению использования памяти и других ресурсов, особенно если количество одновременных соединений велико.
  4. Совместимость с клиентами: Большинство современных клиентов (браузеров, библиотек HTTP) поддерживают Keep-Alive, но важно убедиться, что все клиенты, взаимодействующие с вашим сервером, корректно обрабатывают этот заголовок.
  5. Настройки таймаута: Необходимо правильно настроить таймауты для Keep-Alive соединений, чтобы избежать ситуации, когда соединения остаются открытыми слишком долго, что может привести к исчерпанию доступных соединений.

Использование Keep-Alive может помочь в достижении SLA по задержкам, так как уменьшает время, затрачиваемое на установку соединений, что особенно важно при высоких RPS. Однако, следует внимательно следить за использованием ресурсов и, при необходимости, корректировать параметры, такие как keepalive_timeout в nginx, чтобы оптимально сбалансировать производительность и использование ресурсов.

uwsgi_read_timeout

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

В моем случае uwsgi_read_timeout установлен на 2 секунды, что означает, что Nginx будет ждать до 2 секунд для получения полного ответа от uWSGI-сервера, прежде чем прервать соединение. Это значение должно быть достаточно большим, чтобы покрыть максимальное время обработки запроса приложением, но не слишком большим, чтобы избежать долгих зависаний в случае проблем с сервером.

Note

Имеет смысл установить uwsgi_send_timeout на такое же значение, чтобы обеспечить согласованность в обработке таймаутов.

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

uwsgi_send_timeout

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

В моём случае uwsgi_send_timeout установлен на 2 секунды, что означает, что Nginx будет пытаться отправить данные клиенту в течение 2 секунд, прежде чем разорвать соединение, если данные не были успешно отправлены.

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

Note

Имеет смысл установить uwsgi_read_timeout на такое же значение, чтобы обеспечить согласованность в обработке таймаутов.

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