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

uWSGI для ML-приложений на Python в production среде

1. O uWSGI

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

Особенности uWSGI

  1. Поддержка WSGI: uWSGI полностью поддерживает WSGI, стандартный интерфейс для взаимодействия между веб-серверами и Python-приложениями.
  2. Многопоточность и многопроцессорность: uWSGI позволяет распределять нагрузку между несколькими процессами или потоками, что улучшает производительность.
  3. Масштабируемость: uWSGI легко масштабируется, позволяя добавлять больше процессов или потоков в зависимости от нагрузки.
  4. Поддержка кэширования: uWSGI может поддерживать единый кэш для всех воркеров.
  5. Гибкость: Поддержка множества плагинов и возможность настройки под различные задачи. Например, есть плагин Python.
  6. Надежность и отказоустойчивость: uWSGI обеспечивает надежное выполнение приложений, автоматически перезапуская процессы в случае их сбоя.
  7. Управление ресурсами: uWSGI предоставляет инструменты для управления ресурсами, такими как лимиты на использование памяти и CPU, что помогает избежать перегрузки системы.

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

uWSGI 2.1

Цитата из этого комментария от 2017 года:

... we decided to fix all of the bad defaults (expecially for the python plugin) in the 2.1 branch.

По состоянию на конец 2024 года версия 2.1 так и не выпущена.

2. Ресурсы и документация

  1. uWSGI 2.0 documentation.
  2. uWSGI
  3. Things to know (best practices and “issues”) READ IT !!!.
  4. The Art of Graceful Reloading.
  5. uWSGI Options.
  6. uwsgitop is a top-like command that uses the uWSGI Stats Server to monitor your uwsgi application.
  7. Configuring uWSGI for Production: The defaults are all wrong.

3. Конфиг, оптимизированный для ML-приложения на Python в production среде

Tip

Перед воркерами uWSGI лучше установить reverse-proxy, например, nginx, который будет балансировать нагрузку между ними.

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

uwsgi.ini
##########################################################################################
#  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.
##########################################################################################


##########################################################################################
# uWSGI config file optimized for a Python ML application in a production environment.
#
# Attention! This configuration requires a higher-level reverse proxy, for example
# Nginx (Angie), configured to communicate with uWSGI using the uWSGI protocol
# instead of HTTP.
#
# Docs:
#   1. uWSGI Options:
#   https://uwsgi-docs.readthedocs.io/en/latest/Options.html
#   2. Things to know (best practices and “issues”) READ IT !!!:
#   https://uwsgi-docs.readthedocs.io/en/latest/ThingsToKnow.html
#   3. uWSGI for ML Applications in Python in a Production Environment:
#   https://vkolupaev.com/notebook/mlops/uwsgi-for-ml-applications-in-python-production/
##########################################################################################

[uwsgi]
# Load another sections from the same file.
# See: https://uwsgi-docs.readthedocs.io/en/latest/Configuration.html#ini-files
ini = :x-core
ini = :x-socket
ini = :x-application
ini = :x-python
ini = :x-workers
ini = :x-worker-recycling
ini = :x-buffers-limits
ini = :x-timeouts
ini = :x-http
ini = :x-observability

[x-core]
# Enable strict mode (placeholder cannot be used). Only valid uWSGI options are tolerated.
strict = true

# Enable master process for better management
master = true

# exit instead of brutal reload on SIGTERM (no more needed)
die-on-term = true

[x-socket]
# Never expose a socket speaking the uwsgi protocol to the public network unless you
# know what you are doing!
# Spawns an additional process forwarding requests to a series of workers (think about it
# as a form of shield, at the same level of apache or nginx).

# Socket settings for working with Nginx. uWSGI will listen on this port.
socket = :5000

# When uWSGI and nginx are in different Kubernetes containers, setting up a chmod-socket
# does not make sense.This option is used to manage socket access rights on the file
# system, which is important when uWSGI and nginx work on the same server and
# communicate via a Unix socket.
chmod-socket = 660

# Do not run uWSGI instances as root.
# When uWSGI and nginx are in different Kubernetes containers, setting up this options
# does not make sense.
uid = www-data
gid = www-data

# Removes the Unix socket on shutdown. It doesn't matter when using TCP sockets.
vacuum = true

[x-application]
# Load the WSGI application from the specified module
module = app:get_app()

# Ensure the application is loaded before handling requests
need-app = true

# Load the application before the worker fork
lazy-apps = false

[x-python]
# do not use multiple interpreters (where available)
single-interpreter = true

# set python optimization leve
optimize = 2

[x-workers]
# Number of worker processes
processes = 4

# Enable threading support
enable-threads = true

# Number of threads per worker. For CPU-bound, 1 thread per process is better.
threads = 2

# Improves performance in many processes (?).
thunder-lock = true

[x-worker-recycling]
# Restart workers after this many requests.
# 60 sec * 60 min * 60 RPS
max-requests = 216000

# Restart worker after this many seconds.
# 60 sec * 60 min * 4 hrs
max-worker-lifetime = 14400

# Restart worker after this much resident memory.
reload-on-rss = 45056

# How long to wait before forcefully killing workers.
worker-reload-mercy = 6

[x-buffers-limits]
# Maximum size of request body.
# By default uWSGI allocates a very small buffer (4096 bytes) for the headers of each
# request. If you start receiving “invalid request block size” in your logs, it could
# mean you need a bigger buffer.
# Increase it (up to 65535) with the buffer-size option.
buffer-size = 8192

# The default value is 0.
# Before setting up, make sure that you really know how this option works.
post-buffering = 0

# uWSGI will maintain a queue of this number of incoming connections that can wait
# to be processed. If the queue overflows, new connections will be rejected.
listen = 256

[x-timeouts]
# Timeout for requests (in seconds)
harakiri = 4
socket-timeout = 2

[x-http]
# In this setup, the interaction between nginx and uWSGI takes place
# via a TCP socket, not via HTTP. Therefore, this parameter will have
# no effect on the interaction between nginx and uWSGI.
http-keepalive = true

# In this setup, the interaction between nginx and uWSGI takes place
# via a TCP socket, not via HTTP. Therefore, this parameter will have
# no effect on the interaction between nginx and uWSGI.
http-auto-chunked = false

# Disables Nagle's algorithm
# Effect:
#   1. Reduces latency when sending small packets
#   2. Packets are sent immediately without waiting for buffering
#   3. Useful for applications that require a fast response
#   4. May increase network load due to more packets
# It is recommended to use:
#   1. For real-time applications
#   2. When minimum delay is important
#   3. When sending small packages frequently
tcp-nodelay = true

# Activates TCP keepalive
# Effect:
#   1. Keeps the connection active
#   2. Periodically checks if the connection is active
#   3. Helps to detect "dead" connections
#   4. Clears inactive connections
# It is recommended to use:
#   1. For long connections
#   2. If necessary, the definition of broken connections
#   3. To clean up "hung up" connections
so-keepalive = true

[x-observability]
log-4xx = true
log-5xx = true

# Enable in production!
disable-logging = true

# Enable uWSGI Stats Server to monitor your uwsgi application.
stats = :1717
stats-http = true

# Collect and export metrics in Prometheus format.
enable-metrics = true

# enable memory report
memory-report = true

# automatically set processes name to something meaningful
auto-procname = true

# Note the space.
procname-prefix = "your-app-name "

4. Опции

[x-core]

strict

uwsgi.ini
# Enable strict mode (placeholder cannot be used).
# Only valid uWSGI options are tolerated.
strict = true

You can easily add non-existent options to your config files (as placeholders, custom options, or app-related configuration items). This is a really handy feature, but can lead to headaches on typos. The strict mode (--strict) will disable this feature, and only valid uWSGI options are tolerated.

master

uwsgi.ini
master = true

В контексте uWSGI параметр master управляет использованием мастер-процесса. Когда master = true, uWSGI запускает мастер-процесс, который управляет воркерами (рабочими процессами). Это рекомендуется для большинства приложений, так как позволяет более эффективно управлять воркерами, перезапускать их при необходимости, и обрабатывать сигналы.

Использование мастер-процесса особенно важно в случае, если вы планируете использовать функции, такие как thunder-lock или lazy-apps, которые требуют наличия мастер-процесса для корректной работы.

die-on-term

uwsgi.ini
die-on-term = true

Параметр die-on-term в конфигурации uWSGI указывает, что процесс uWSGI должен завершиться, если получает сигнал завершения (SIGTERM). Это полезно в сценариях, где вы хотите, чтобы uWSGI корректно завершал все свои процессы и освобождал ресурсы при остановке сервера или при перезапуске контейнера в Kubernetes.

Когда die-on-term установлен в true, uWSGI будет завершать все свои рабочие процессы и завершать свою работу при получении сигнала SIGTERM. Это обеспечивает более предсказуемое и управляемое завершение работы приложения, что особенно важно в средах, где требуется корректное освобождение ресурсов и завершение всех операций перед остановкой.

TIll uWSGI 2.1, by default, sending the SIGTERM signal to uWSGI means "brutally reload the stack" while the convention is to shut an application down on SIGTERM.

[x-socket]

socket

uwsgi.ini
module = socket = :<port>

В чем будет разница, если в конфиге uWSGI указать socket = :<port> или http = :<port>?

Когда вы настраиваете uWSGI, вы можете указать, как именно сервер будет принимать входящие соединения. Разница между использованием socket = :<port> и http = :<port> заключается в протоколе, который будет использоваться для обработки запросов.

  1. socket = :5000:

    • В этом случае uWSGI будет слушать на сокете, используя протокол uWSGI или другой низкоуровневый протокол (например, FastCGI).
    • Это более эффективно для взаимодействия с веб-серверами, такими как Nginx или Apache, которые могут выступать в роли прокси-сервера и передавать запросы приложению через этот сокет.
    • Обычно используется в производственных средах, где uWSGI работает за обратным прокси-сервером.
  2. http = :5000:

    • Здесь uWSGI будет слушать HTTP-запросы напрямую.
    • Это удобно для разработки и тестирования, так как позволяет напрямую обращаться к uWSGI через браузер или HTTP-клиент без необходимости в дополнительном веб-сервере.
    • Однако это может быть менее эффективно в производственной среде по сравнению с использованием сокетов и прокси-сервера.

Выбор между этими двумя опциями зависит от вашего окружения и требований. Для разработки и тестирования http = :<port> может быть более удобным, тогда как для производственной среды обычно предпочтительнее использовать socket = :<port> в сочетании с веб-сервером, таким как Nginx (ну или Angie:-).

chmod-socket

uwsgi.ini
chmod-socket = 660

Параметр chmod-socket в конфигурации uWSGI используется для установки прав доступа к сокету, который создается для взаимодействия с веб-сервером или для прослушивания входящих соединений. Значение этого параметра указывает на права доступа в формате, аналогичном команде chmod в Unix-системах.

chmod-socket = 666 означает, что сокет будет иметь права rw-rw-rw-, то есть чтение и запись разрешены для всех пользователей. Это может быть полезно, если вы хотите, чтобы несколько процессов или пользователей могли взаимодействовать с сокетом, но также может представлять риск с точки зрения безопасности, если сокет доступен для записи всем пользователям системы.

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

В этом случае uid и gid должны соответствовать пользователю и группе, под которыми работает nginx. Это необходимо для того, чтобы nginx мог взаимодействовать с uWSGI через сокет.

vacuum

uwsgi.ini
vacuum = true

Параметр vacuum в конфигурации uWSGI отвечает за очистку временных файлов и сокетов после завершения работы процесса uWSGI. Когда этот параметр установлен в true, uWSGI автоматически удаляет все временные файлы и сокеты, которые были созданы во время работы, после завершения процесса. Это полезно для предотвращения накопления ненужных файлов и освобождения системных ресурсов. В контексте Kubernetes, где контейнеры могут часто перезапускаться, использование vacuum = true помогает поддерживать чистоту в файловой системе.

[x-application]

module

Опция module в конфигурации uWSGI указывает на модуль Python, который должен быть загружен и использован в качестве WSGI-приложения. Это фактически точка входа для вашего веб-приложения.

uwsgi.ini
module = app:get_app()

Приведенная выше настройка означает, что uWSGI будет искать модуль app и вызывать функцию get_app(), которая должна возвращать объект WSGI-приложения. Этот объект будет использоваться для обработки входящих HTTP-запросов.

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

need-app

uwsgi.ini
need-app = true

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

Now things have changed but there are still dozens of paying customers that use this kind of setup, and by default we do not change default unless after a loooong deprecation phase.

Если не включить, то может случиться ситуация, когда uWSGI стартовал без приложения и начнёт отдавать 4xx и 5xx.

lazy-app

При включении опции lazy-apps = true в uWSGI каждый рабочий процесс (worker) загружает приложение заново после форка. Это отличается от стандартного поведения, когда приложение загружается один раз в основном процессе, а затем форкается для создания рабочих процессов.

Основные причины увеличения потребления RAM при использовании lazy-apps = true:

  1. Отсутствие общей памяти: При стандартном подходе (без lazy-apps = true) рабочие процессы разделяют память, занятую приложением, благодаря механизму copy-on-write. Это означает, что пока данные не изменяются, они остаются общими для всех процессов. При использовании lazy-apps = true каждый процесс загружает своё собственное независимое приложение, что увеличивает общий объём используемой памяти.
  2. Инициализация ресурсов: Каждый процесс может заново инициализировать ресурсы, такие как соединения с базой данных, кэш и другие внешние сервисы, что также может увеличить потребление памяти.
  3. Библиотеки и зависимости: Если приложение использует большие библиотеки или зависимости, их копии будут загружены в память для каждого рабочего процесса, что также увеличивает общий объём используемой памяти.

Использование lazy-apps = true может быть полезно в некоторых сценариях, например, когда необходимо, чтобы каждый процесс имел свою собственную изолированную среду, но это приходит с компромиссом в виде увеличенного потребления памяти.

Tip

Хорошее пояснение логики работы lazy-app: Preforking VS lazy-apps VS lazy.

[x-python]

single-interpreter

uwsgi.ini
single-interpreter = true

Multiple interpreters are cool but there are reports on some C extensions that do not cooperate well with them.

Опция single-interpreter = true в конфигурации uWSGI указывает на использование единственного интерпретатора Python для всех приложений, работающих в одном процессе uWSGI.

По умолчанию uWSGI позволяет размещать несколько services в каждом worker процессе. uWSGI может создавать несколько интерпретаторов Python, если это необходимо, например, для изоляции различных приложений. Однако это может привести к увеличению потребления памяти и усложнению управления памятью.

Использование single-interpreter = true может быть полезно в следующих случаях:

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

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

optimize

uwsgi.ini
optimize = 2

См. документацию Python: PYTHONOPTIMIZE.

[x-workers]

processes

Сколько указывать processes?

There is no magic rule for setting the number of processes or threads to use. It is very much application and system dependent. Simple math like processes = 2 * cpucores will not be enough. You need to experiment with various setups and be prepared to constantly monitor your apps. uwsgitop could be a great tool to find the best values.

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

enable-threads

uwsgi.ini
enable-threads = true

By default, the Python plugin does not initialize the GIL. This means your app-generated threads will not run.

This "strange" default behaviour is for performance reasons, no shame in that.

Включение параметра enable-threads в конфигурации uWSGI позволяет использовать многопоточность в рамках каждого процесса. Это может быть полезно для приложений, которые выполняют операции I/O или требуют параллельной обработки, но для CPU-bound задач, таких как ML-приложения, многопоточность может не всегда приводить к улучшению производительности из-за GIL (Global Interpreter Lock) в Python.

Влияние данной опции нужно тестировать на конкретной реализации ML-приложения.

threads

Параметр threads определяет количество потоков, которые будет использовать каждый процесс uWSGI. Потоки могут быть полезны для I/O-bound задач, но для CPU-bound задач, таких как ML-приложения, они могут не давать значительного прироста производительности и даже могут снижать её из-за накладных расходов на переключение контекста.

Влияние данной опции нужно тестировать на конкретной реализации ML-приложения.

thunder-lock

В конфигурации uWSGI параметр thunder-lock используется для улучшения производительности при работе с несколькими процессами и потоками. Вот как он влияет на конфиг:

  1. Синхронизация доступа к ресурсам: thunder-lock помогает синхронизировать доступ к ресурсам между процессами и потоками. Это особенно важно, когда используется параметр enable-threads = true, так как в этом случае в каждом процессе могут быть активны несколько потоков.
  2. Улучшение производительности: Включение thunder-lock может улучшить производительность приложения за счет уменьшения накладных расходов на блокировки. Это достигается путем оптимизации механизма блокировки, что особенно полезно при высокой нагрузке.
  3. Предотвращение дедлоков: Использование thunder-lock может помочь избежать дедлоков, которые могут возникнуть при одновременном доступе нескольких процессов и потоков к общим ресурсам.

В приведенном ниже конфиге processes = 4 и threads = 1, что означает, что у uWSGI будет 4 процесса, каждый из которых может использовать один поток. Включение thunder-lock в этом случае может помочь более эффективно управлять ресурсами и улучшить общую производительность приложения.

uwsgi.ini
processes = 4
enable-threads = true
threads = 1
thunder-lock = true

[x-worker-recycling]

Периодический рестарт workers может минимизировать влияние ошибок в состоянии и утечек памяти.

max-requests

uwsgi.ini
# Restart workers after this many requests.
# 60 sec * 60 min * 60 RPS
max-requests = 216000

Этот параметр задает фиксированное количество запросов, после обработки которых рабочий процесс будет перезапущен. Например, если max-requests установлен в 1000, то каждый рабочий процесс будет перезапущен после обработки 1000 запросов.

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

max-requests-delta

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

Например, если max-requests установлен в 1000, а max-requests-delta в 100, то рабочие процессы будут перезапускаться после обработки от 1000 до 1100 запросов (случайное значение в этом диапазоне).

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

Warning

Опция присутствует в документации, но в uWSGI v2.0.x она не реализована.

См. этот комментарий.

max-worker-lifetime

uwsgi.ini
# Restart worker after this many seconds.
# 60 sec * 60 min * 4 hrs
max-worker-lifetime = 14400

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

Рекомендации:

  • Оптимальное значение: Установите max-worker-lifetime в зависимости от стабильности вашего приложения и наличия утечек памяти. Обычно это значение может быть от нескольких часов до суток.
  • Совместимость: Убедитесь, что перезапуск воркеров не приводит к потере данных или сбоев в обработке запросов. Используйте параметры, такие как lazy-apps или reload-on-rss, чтобы минимизировать влияние на производительность.
  • Мониторинг: Следите за использованием памяти и временем отклика, чтобы определить оптимальное значение для вашего приложения.

reload-on-rss

uwsgi.ini
# Restart worker after this much resident memory.
reload-on-rss = 45056
Параметр reload-on-rss в uWSGI используется для автоматической перезагрузки рабочих процессов, когда они достигают определенного порога использования памяти (RSS - Resident Set Size).

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

Note

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

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

worker-reload-mercy

uwsgi.ini
# How long to wait before forcefully killing workers.
worker-reload-mercy = 6

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

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

Рекомендации:

  1. Значение должно превышать максимальное время обработки запроса в приложении. Например, если ваш p95 времени обработки запроса составляет <100 мс, вы можете установить worker-reload-mercy в 1-2 секунды, чтобы учесть возможные задержки.
  2. Значение должно быть немного больше, чем значение harakiri, чтобы дать воркерам достаточно времени для завершения текущих запросов перед перезапуском. Это обеспечит плавный перезапуск воркеров без прерывания обработки запросов, особенно если у вас есть длительные операции, которые могут занять больше времени, чем обычно.
  3. Значение должно быть достаточно большим, чтобы учесть возможные задержки в обработке, но не слишком большим, чтобы не задерживать перезапуск воркеров при необходимости.
  4. Тестируйте изменения в конфигурации на нагрузочном тестировании, чтобы убедиться, что перезапуск воркеров не влияет на производительность и доступность вашего приложения.

[x-buffers-limits]

buffer-size

uwsgi.ini
# Maximum size of request body.
# By default uWSGI allocates a very small buffer (4096 bytes) for the headers of each
# request. If you start receiving “invalid request block size” in your logs, it could
# mean you need a bigger buffer.
# Increase it (up to 65535) with the buffer-size option.
buffer-size = 8192

Параметр buffer-size в uWSGI определяет размер буфера для чтения данных из сокета. Это важно для обработки HTTP-запросов, так как буфер используется для хранения данных запроса до их обработки приложением. Если размер буфера слишком мал, то запросы, превышающие этот размер, могут быть обрезаны или не обработаны корректно.

Для CPU-bound ML-приложения, получающего JSON в POST-запросах, важно учитывать размер данных, которые могут быть отправлены в одном запросе. Если есть вероятность, что JSON payload может значительно увеличиться в будущем, то стоит предусмотреть запас.

По умолчанию, размер буфера в uWSGI составляет 4096 байт (4 КБ). Это значение может быть достаточным для небольших запросов, но если вы ожидаете более крупные запросы, стоит увеличить этот параметр.

Рекомендации по установке buffer-size:

  1. Оцените максимальный размер запроса, который ваше приложение может получить.
  2. Установите buffer-size с запасом, чтобы учесть возможные увеличения данных. Например, если максимальный размер запроса составляет 8 КБ, установите buffer-size на 16 КБ (16384 байта).
  3. Проведите нагрузочное тестирование, чтобы убедиться, что выбранный размер буфера оптимален и не приводит к потере данных или увеличению времени обработки.

http-buffer-size

http-buffer-size — это параметр, который определяет размер буфера для HTTP-запросов. Этот параметр важен для обработки входящих HTTP-запросов, особенно когда они содержат большие объемы данных, такие как JSON-пейлоады.

Рекомендации:

  1. Увеличение размера буфера: Если ваши POST-запросы содержат большие JSON-объекты, может быть полезно увеличить http-buffer-size. Например, можно установить его на 8192 или 16384 байт, чтобы избежать фрагментации данных и улучшить производительность при обработке больших запросов.
  2. Тестирование: После изменения этого параметра рекомендуется провести нагрузочное тестирование, чтобы убедиться, что приложение обрабатывает запросы эффективно и без ошибок.
  3. Совместимость с buffer-size и post-buffering: Убедитесь, что значения buffer-size и post-buffering также соответствуют увеличенному http-buffer-size, чтобы избежать узких мест в обработке данных.

Warning

При использовании параметра socket = :<port> вместо http = :<port>, uWSGI работает с сокетами напрямую, а не через HTTP-протокол. В этом случае параметр http-buffer-size не имеет смысла, так как он используется для настройки размера буфера HTTP-запросов, когда uWSGI работает в режиме HTTP.

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

post-buffering

uwsgi.ini
# The default value is 0.
# Before setting up, make sure that you really know how this option works.
post-buffering = 0

Параметр post-buffering в uWSGI определяет, сколько байт данных из POST-запроса будет буферизовано в памяти перед тем, как передать их в приложение. Это может быть полезно, если приложение не может обрабатывать данные по частям и требует, чтобы весь запрос был доступен сразу.

Когда стоит использовать post-buffering:

  1. Защита от медленных клиентов: Если вы ожидаете, что клиенты могут отправлять данные медленно, буферизация может помочь избежать блокировки рабочих процессов.
  2. Ограничение памяти: Если ваше приложение обрабатывает большие тела запросов и вы хотите ограничить использование памяти, post-buffering может помочь, так как uWSGI будет использовать временные файлы на диске.

Когда post-buffering не нужен:

  1. Маленькие тела запросов: Если тела запросов небольшие, post-buffering может быть избыточным.
  2. Высокая производительность: Если ваше приложение уже оптимизировано и нет проблем с производительностью или памятью, post-buffering может не дать значительных преимуществ.

В uWSGI параметр post-buffering по умолчанию имеет значение 0. Это означает, что без явного указания этого параметра, uWSGI не будет буферизовать тело POST-запросов, и данные будут передаваться приложению по мере их поступления.

Для CPU-bound ML-приложения на Python, которое получает JSON-пейлоады, значение post-buffering следует выбирать с учетом следующих факторов:

  1. Размер данных: Если у вас есть ограничения по памяти или если вы ожидаете, что входящий JSON может значительно увеличиться, это стоит учитывать.
  2. Память сервера: Убедитесь, что сервер имеет достаточно памяти для буферизации POST-запросов. Если у вас много одновременных запросов, это может привести к значительному потреблению памяти.
  3. Обработка данных: Если ваше приложение обрабатывает данные постепенно или если есть задержки при обработке, может быть полезно буферизовать больше данных, чтобы избежать блокировок.

Для начала, вы можете установить post-buffering на значение, которое превышает средний размер ваших POST-запросов. Например, если средний размер вашего JSON-пейлоада составляет около 1-2 КБ, вы можете установить post-buffering на 4096 байт (4 КБ) или 8192 байт (8 КБ). Это должно быть достаточно для буферизации большинства запросов целиком.

Важно протестировать приложение с разными значениями post-buffering, чтобы найти оптимальное значение, которое обеспечит баланс между использованием памяти и производительностью. Также следите за поведением приложения под нагрузкой, чтобы убедиться, что выбранное значение не приводит к проблемам с памятью или производительностью.

Если отключить post-buffering, то uWSGI на старте будет выдавать такое предупреждение:

*** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers ***

listen

uwsgi.ini
# uWSGI will maintain a queue of this number of incoming connections that can wait
# to be processed. If the queue overflows, new connections will be rejected.
listen = 256

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

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

Note

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

[x-timeouts]

harakiri

uwsgi.ini
harakiri = 4

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

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

This option will SIGKILL workers after a specified number of seconds. Without this feature, a stuck process could stay stuck forever.

socket-timeout

uwsgi.ini
socket-timeout = 2

socket-timeout — это параметр, который определяет максимальное время ожидания в секундах для операций ввода-вывода на сокете. В контексте uWSGI, это время, в течение которого сервер будет ожидать завершения операции чтения или записи на сокете. Если операция не завершится в течение указанного времени, она будет прервана.

Рекомендации по настройке socket-timeout:

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

  2. Оптимизация: Учитывая, что ваше приложение должно обрабатывать запросы с p95 < 100 мс и у вас есть SLA на p95@300 мс, вы можете уменьшить socket-timeout до более разумного значения, например, 1-2 секунды. Это позволит быстрее освобождать ресурсы в случае зависших соединений и улучшит общую отзывчивость системы.

  3. Совместимость с другими параметрами: Убедитесь, что socket-timeout согласован с harakiri, чтобы избежать ситуаций, когда разные таймауты конфликтуют друг с другом.

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

Рекомендации по настройке socket-timeout:

  1. Анализ нагрузки: Если ваше приложение обрабатывает большие объемы данных или сложные вычисления, вам может потребоваться увеличить значение socket-timeout, чтобы избежать преждевременного разрыва соединений.
  2. Сетевые условия: Если ваше приложение работает в условиях нестабильной сети или с высокой задержкой, также рекомендуется увеличить socket-timeout.
  3. Балансировка с harakiri: Убедитесь, что значение socket-timeout согласуется с параметром harakiri, который завершает запросы, выполняющиеся дольше указанного времени. Обычно harakiri должно быть больше, чем socket-timeout, чтобы избежать преждевременного завершения запросов.
  4. Тестирование: Проведите нагрузочное тестирование с различными значениями socket-timeout, чтобы определить оптимальное значение для вашего приложения.

Увеличение socket-timeout может помочь в ситуациях, когда приложение обрабатывает длительные запросы или работает в условиях высокой сетевой задержки. Однако не забывайте, что слишком большое значение может привести к увеличению времени ожидания для клиентов в случае реальных проблем с сетью или сервером.

http-timeout

uwsgi.ini
http-timeout = 2

Параметр http-timeout в конфигурации uWSGI определяет максимальное время ожидания для HTTP-запросов. Это время, в течение которого uWSGI будет ждать завершения обработки HTTP-запроса, прежде чем считать его неудачным и прервать соединение.

Warning

В моём сетапе использование параметра http-timeout в конфигурации uWSGI не имеет смысла, так как я использую сокет для взаимодействия между Nginx и uWSGI, а не HTTP.

Параметр http-timeout применяется только в случае, если uWSGI работает в режиме HTTP-сервера.

Поскольку я использую Nginx для балансировки нагрузки и проксирования запросов, именно его параметры uwsgi_read_timeout и uwsgi_send_timeout будут определять таймауты для HTTP-запросов.

[x-http]

http-keepalive

uwsgi.ini
# HTTP 1.1 keepalive support (non-pipelined) requests
http-keepalive = true

Параметр http-keepalive в конфигурации uWSGI отвечает за поддержку постоянных соединений (keep-alive) для HTTP-запросов. Когда этот параметр включен (true), uWSGI будет пытаться поддерживать открытое соединение с клиентом после отправки ответа, чтобы использовать его для последующих запросов.

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

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

Note

В моём сетапе взаимодействие между nginx и uWSGI происходит через Unix-сокет, а не через HTTP. Поэтому этот параметр не будет иметь эффекта на взаимодействие между nginx и uWSGI.

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

http-auto-chunked

Параметр http-auto-chunked в uWSGI отвечает за автоматическое использование chunked transfer encoding для HTTP-ответов. Это полезно, когда размер ответа заранее неизвестен или когда вы хотите начать отправку данных клиенту до того, как весь ответ будет сформирован.

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

Включение параметра http-auto-chunked в uWSGI имеет смысл, когда размер ответа превышает определенный порог, который может варьироваться в зависимости от конкретной конфигурации и требований приложения. Обычно это актуально для ответов, размер которых превышает несколько килобайт.

Если ответы могут быть достаточно большими (например, более 8-16 КБ), включение http-auto-chunked может помочь оптимизировать передачу данных, особенно если клиент ожидает потоковую передачу данных. Это позволяет серверу отправлять данные по частям, не дожидаясь формирования всего ответа, что может улучшить время отклика и снизить нагрузку на память.

Однако, если ответы обычно меньше этого порога, то включение http-auto-chunked может не дать значительных преимуществ. Важно протестировать и измерить производительность с включенным и выключенным параметром, чтобы определить его влияние на конкретную рабочую нагрузку.

Note

В моём сетапе взаимодействие между nginx и uWSGI происходит через Unix-сокет, а не через HTTP. Поэтому этот параметр не будет иметь эффекта на взаимодействие между nginx и uWSGI.

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

tcp-nodelay

uwsgi.ini
# Disables Nagle's algorithm
# Effect:
#   1. Reduces latency when sending small packets
#   2. Packets are sent immediately without waiting for buffering
#   3. Useful for applications that require a fast response
#   4. May increase network load due to more packets
# It is recommended to use:
#   1. For real-time applications
#   2. When minimum delay is important
#   3. When sending small packages frequently
tcp-nodelay = true

Параметр tcp-nodelay в конфигурации uWSGI (и других сетевых приложений) управляет использованием алгоритма Нейгла для соединений TCP. Алгоритм Нейгла предназначен для уменьшения количества мелких пакетов, отправляемых по сети, путем буферизации данных до тех пор, пока не будет накоплено достаточно информации для отправки одного большого пакета. Это может уменьшить нагрузку на сеть, но также может привести к задержкам в передаче данных.

Когда tcp-nodelay установлен в true, это отключает алгоритм Нейгла, что позволяет отправлять данные сразу же, без задержек. Это может быть полезно для приложений, где важна минимальная задержка передачи данных, например, в случае с ML приложением, где важно соблюдать SLA по задержкам.

Учитывая требования по задержкам (p95@250 ms, p99@300 ms) и то, что приложение обрабатывает запросы достаточно быстро (p95 < 200 ms), использование tcp-nodelay = true является оправданным решением для минимизации сетевых задержек и улучшения общей производительности.

so-keepalive

uwsgi.ini
# Activates TCP keepalive
# Effect:
#   1. Keeps the connection active
#   2. Periodically checks if the connection is active
#   3. Helps to detect "dead" connections
#   4. Clears inactive connections
# It is recommended to use:
#   1. For long connections
#   2. If necessary, the definition of broken connections
#   3. To clean up "hung up" connections
so-keepalive = true

Параметр so-keepalive в конфигурации uWSGI отвечает за включение механизма TCP Keep-Alive на уровне сокетов. Это системная опция, которая позволяет поддерживать соединение активным, даже если в течение длительного времени не происходит обмен данными.

Когда so-keepalive включен, операционная система периодически отправляет контрольные пакеты (keep-alive packets) для проверки, что соединение всё ещё активно. Это помогает обнаруживать "мертвые" соединения и освобождать ресурсы, если клиент или сервер больше не доступны.

Использование so-keepalive может быть полезным для поддержания стабильных соединений между компонентами системы, особенно если они взаимодействуют через сеть с потенциально переменным качеством соединения. Однако, стоит учитывать, что избыточное использование keep-alive пакетов может привести к дополнительной нагрузке на сеть, поэтому их использование должно быть обоснованным.

[x-observability]

disable-logging

uwsgi.ini
# Enable in production!
disable-logging = true
В конфигурации uWSGI параметр disable-logging = true отключает ведение журнала (логирование) для всех HTTP-запросов, обрабатываемых приложением. Это может быть полезно для уменьшения нагрузки на систему, особенно если приложение обрабатывает большое количество запросов и логирование каждого из них не требуется. Однако, это также означает, что вы не будете иметь доступ к журналам запросов для диагностики и анализа, что может затруднить отладку и мониторинг работы приложения.

Если вам необходимо логирование для целей мониторинга или отладки, рекомендуется установить disable-logging = false или использовать более избирательные методы логирования, чтобы снизить нагрузку, но при этом иметь доступ к необходимой информации.

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

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

log-4xx

uwsgi.ini
log-4xx = true

Параметр log-4xx в конфигурации uWSGI отвечает за логирование HTTP-ответов с кодами состояния 4xx. Эти коды состояния указывают на ошибки клиента, такие как "404 Not Found" или "403 Forbidden". Когда log-4xx установлен в true, uWSGI будет записывать в журнал все запросы, которые возвращают коды состояния 4xx. Это может быть полезно для отладки и мониторинга, чтобы выявлять и анализировать проблемы, связанные с клиентскими ошибками.

log-5xx

uwsgi.ini
log-5xx = true

Параметр log-5xx в конфигурации uWSGI отвечает за логирование всех HTTP-ответов с кодами состояния 5xx, которые указывают на ошибки сервера. Когда этот параметр установлен в true, uWSGI будет записывать в журнал все случаи, когда сервер возвращает клиенту ошибку 5xx. Это полезно для мониторинга и отладки, так как позволяет быстро выявлять и анализировать проблемы, связанные с внутренними ошибками сервера.

Пример log-записи

Лог, который предоставляет детальную информацию о ресурсоемкости и производительности обработки конкретного HTTP-запроса в uwsgi:

{address space usage: 13296496640 bytes/12680MB} {rss usage: 12713156608 bytes/12124MB} [pid: 23|app: 0|req:
570/2259] 172.20.0.8 () {40 vars in 535 bytes} [XXX XXX XX XX:XX:XX XXXX] POST /api/v1/endpoint => generated 38
bytes in 1 msecs (HTTP/1.1 200) 4 headers in 119 bytes (1 switches on core 0)

Разбор лога на молекулы:

  1. {address space usage: 13296496640 bytes/12680MB}: Это показывает объем адресного пространства, используемого процессом. Адресное пространство включает в себя все выделенные процессу виртуальные адреса, которые могут включать как фактически используемую память, так и память, которая зарезервирована, но не используется.
  2. {rss usage: 12713156608 bytes/12124MB}: RSS (Resident Set Size) — это объем физической памяти, используемой процессом. Это фактически используемая память, загруженная в оперативную память (RAM).
  3. [pid: 23|app: 0|req: 570/2259]:
    • pid: 23: Идентификатор процесса, который обрабатывает запрос.
    • app: 0: Индекс приложения, которое обрабатывает запрос. В uwsgi можно запускать несколько приложений, и они индексируются начиная с 0.
    • req: 570/2259: Количество запросов, обработанных этим процессом (570) и общее количество запросов, обработанных всеми процессами (2259).
  4. 172.20.0.8: IP-адрес клиента, который отправил запрос.
  5. {40 vars in 535 bytes}: Количество переменных окружения (40) и общий объем данных этих переменных (535 байт), переданных с запросом.
  6. [XXX XXX XX XX:XX:XX XXXX]: Время и дата, когда запрос был обработан.
  7. POST /api/v1/endpoint: Метод HTTP (POST) и URL, к которому был сделан запрос.
  8. => generated 38 bytes in 1 msecs: Сервер сгенерировал ответ размером 38 байт за 1 миллисекунду.
  9. (HTTP/1.1 200): Версия протокола HTTP и код состояния ответа (200 — успешный запрос).
  10. 4 headers in 119 bytes: Количество заголовков в ответе (4) и общий объем данных этих заголовков (119 байт).
  11. (1 switches on core 0): Количество переключений контекста (1) на ядре процессора (core 0), которые произошли во время обработки запроса.

Note

В логах uWSGI сообщение вида (1 switches on core 0) относится к информации о работе планировщика зелёных потоков (green threads) или корутин. Это сообщение указывает на количество переключений контекста, которые произошли на определённом ядре процессора:

  1. 1 switches: Это количество переключений контекста, которые произошли. Переключение контекста — это процесс, при котором выполнение программы переключается с одного потока на другой. В контексте uWSGI это может быть связано с использованием зелёных потоков или корутин, таких как те, что предоставляет библиотека gevent.
  2. on core 0: Это указывает на ядро процессора, на котором происходят эти переключения. В данном случае это ядро 0.

stats

uwsgi.ini
stats = :1717

В uWSGI параметр stats используется для включения сбора статистики и метрик о работе сервера uWSGI через Unix-сокет или TCP-сокет. Этот параметр позволяет указать адрес и порт, на котором uWSGI будет предоставлять информацию о текущем состоянии своих процессов, таких как количество активных воркеров, использование памяти, количество обработанных запросов и другие метрики.

В данном случае, я использую TCP-сокет на порту 1717. Я могу подключиться к этому порту с помощью инструментов, таких как nc (netcat), чтобы получить статистику в формате JSON.

Warning

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

stats-http

uwsgi.ini
stats-http = true

Параметр stats-http в конфигурации uWSGI позволяет включить HTTP-интерфейс для получения статистики о работе uWSGI. Когда этот параметр установлен в true, uWSGI открывает HTTP-эндпоинт, через который можно получить информацию о текущем состоянии серверов, таких как количество активных воркеров, количество обработанных запросов, использование памяти и другие метрики.

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

Рекомендуется использовать этот параметр в сочетании с параметром stats, который указывает, на каком порту и адресе будет доступен HTTP-интерфейс для статистики. Если stats = :1717, то что означает, что статистика будет доступна по адресу http://<адрес_сервера>:1717.

Warning

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

enable-metrics

uwsgi.ini
enable-metrics = true

enable-metrics используется для включения системы метрик в uWSGI. Это позволяет собирать и экспортировать метрики в формате, совместимом с системами мониторинга, такими как Prometheus.

stats, в отличие от enable-metrics, используется для предоставления информации о состоянии uWSGI через HTTP или UNIX сокет. Это позволяет получать статистику о работе uWSGI в реальном времени.

memory-report

uwsgi.ini
memory-report = true

Параметр memory-report в конфигурации uWSGI используется для включения периодической отчетности о потреблении памяти каждым воркером. Когда этот параметр установлен в true, uWSGI будет выводить информацию о том, сколько памяти использует каждый процесс воркера.

Информация о потреблении памяти выводится в стандартный журнал uWSGI. Обычно это тот же журнал, куда выводятся другие логи uWSGI, такие, как ошибки и информация о запросах. Путь к этому журналу может быть задан в конфигурации uWSGI с помощью параметра logto или logto2. Если эти параметры не указаны, то по умолчанию информация выводится в стандартный вывод (stdout) или стандартный вывод ошибок (stderr), в зависимости от того, как настроена система и как запущен uWSGI.

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

[uwsgi]
logto = /var/log/uwsgi/memory_report.log

К тому же, когда параметр memory-report = true включен в конфигурации uWSGI, информация о потреблении памяти будет выводиться в отчет, доступный через stats-http.

Как мониторить утилизацию ресурсов и нагрузку на воркеры?

Для мониторинга потребления ресурсов использовать uwsgitop. В конфиге uWSGI указать:

uwsgi.ini
# Enable uWSGI Stats Server to monitor your uwsgi application.
stats = :1717
stats-http = true

# Always check the memory usage of your apps.
memory-report = true

В контейнере запускаем:

uwsgitop http://127.0.0.1:1717

auto-procname

uwsgi.ini
auto-procname = true
По умолчанию, имена процессов workers — это команды, которые были использованы для их старта. Если включить данный флаг, uWSGI будет именовать процессы примерно так: master, worker 1, woker 2, и т.д. Чтобы исключить коллизии именования, используйте procname-prefix.

Для обогащения информации о процессах можно использовать uWSGI API: uwsgi.setprocname().

procname-prefix

uwsgi.ini
# Note the space.
procname-prefix = "your-app-name "

Параметр procname-prefix в конфигурации uWSGI используется для добавления префикса к имени процесса. Это может быть полезно для идентификации процессов uWSGI в системных утилитах, таких как top или ps, особенно когда на одном сервере работает несколько приложений или экземпляров uWSGI. В данном случае, префикс "your-app-name " будет добавлен к имени каждого процесса uWSGI, что упростит мониторинг и управление процессами, связанными с вашим приложением.

5. Additional uWSGI features

Dynamic Worker Scaling

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

uwsgi.ini
cheaper-algo = busyness

# Maximum number of workers allowed.
processes = 500

# Minimun number of workers allowed.
cheaper = 8

# Workers created at startup.
cheaper-initial = 16

# Length of a cycle in seconds.
cheaper-overload = 1

# How many workers to spawn at a time.
cheaper-step = 16

# How many cycles to wait before killing.
cheaper-busyness-multiplier = 30

# Below this threshold, kill workers.
cheaper-busyness-min = 20

# Above this threshold, spawn new wokers.
cheaper-busyness-max = 70

# Spawn emergency workers if > queue size.
cheaper-busyness-backlog-alert = 16

# How many emergency workers to spawn.
cheaper-busyness-backlog-step = 2

Allowing Workers to Receive Signals

uwsgi.ini
py-call-osafterfork = true
По умолчанию, workers, неспособны получать сигналы OS. Этот флаг позволяет им получать такие сигналы, например signal.alarm.

Это необходимо, если вы намерены использовать модуль signal в worker процессах.

py-call-osafterfork — это параметр конфигурации uWSGI, который управляет вызовом функции os.after_fork() после того, как процесс uWSGI форкнут. Это полезно в контексте Python-приложений, которые используют библиотеки, требующие выполнения определенных действий после форкинга процесса (например, повторное открытие файловых дескрипторов или сокетов).

Рекомендации:

  • Когда использовать: Если ваше приложение или используемые библиотеки требуют выполнения специфических операций после форкинга, вы можете установить этот параметр в true.
  • Совместимость: Убедитесь, что используемые библиотеки поддерживают вызов os.after_fork(). Если нет необходимости в таких действиях, лучше оставить этот параметр по умолчанию (обычно false), чтобы избежать ненужных вызовов.

Cron/Timer

The uWSGI master process can manage periodic execution of arbitrary code.

import uwsgi

def periodic_task(signal: int):
    print(f"Received signal {signal}")

# execute every 20 minutes on the first available worker
uwsgi.add_timer(99, 1200)

# execute on the 20th minute of every hour, every day
# minute, hour, day ,month, weekday
uwsgi.add_cron(99, 20, -1, -1 , -1 ,-1)

Timers are also available as decorators from uwsgidecorators module.

import uwsgidecorators

@uwsgidecorators.timer(1200)
def periodic_task(signal: int):
    print(f"Received signal {signal}")
    do_some_work()

Locks

The uwsgi module provides locks to synchronize critical sections between workers.

import uwsgi

def critical_code():
    uwsgi.lock()
    do_some_important_stuff()
    uwsgi.unlock()

The Cache Subsystem

uWSGI provides an in-memory key-value cache to share between your workers.

--cache2 name=mycache,items=150000,blocksize=8,keysize=20

Keys or values that are too big for the cache will silently fail to insert.

import uwsgi

uwsgi.cache_set(key, value, timeout)
uwsgi.cache_get(key)

# atomic increments!
uwsgi.cache_inc(key, amount)
uwsgi.cache_dec(key, amount)

Mules

uWSGI mules are extra processes designated to handle tasks asynchronously from the workers serving requests.

You can start one with --mule and send tasks to it in your Python code.

from uwsgidecorators import timer

# execute this function every minute on an available mule
#timer(60, target="mule")
def do_some_work(signal: int) -> None:
    pass

Что дальше?

  1. Нашли эту статью полезной? Поделитесь ею и помогите распространить знания!
  2. Нашли ошибку или есть идеи 💡 о том, что и как я могу улучшить? Напишите мне в Telegram.
  3. Хотите узнать обо мне больше? Читайте здесь.