Какой способ является наиболее эффективным для запуска сервера Flask при высокой нагрузке на процессор?

Как можно организовать выполняемые вычисления на странице сайта так, чтобы они не блокировали другие части сайта? Пробовал использовать gevent и eventlet совместно с gunicorn, но они имеют ограничения, которые могут вызывать проблемы. Также использовал дефолтный режим threading и метод flask-socketio start_background_task, но предполагаю, что они используют только одно ядро. Интересует возможность реализации этого варианта настроек. Документацию flask-socketio изучил и нашел вариант с запуском дополнительных серверов и балансировкой через nginx, но это не дало ожидааемых результатов, так как сокеты отправляют запросы в разные места, вместо того чтобы направлять их на один сервер.
  • 17 января 2024 г. 12:20
Ответы на вопрос 3
Для запуска сервера Flask при высокой нагрузке обычно используются Production-ready WSGI сервера в связке с веб-серверами, предназначенными для масштабирования и обработки множества запросов. Наиболее рекомендуемые подходы:

1. **Использование Gunicorn с многопроцессорным режимом:**
   Gunicorn позволяет запускать несколько рабочих процессов (работников), каждый из которых запускает свой экземпляр Flask приложения. Вы можете определить количество рабочих с помощью параметра `--workers`, и это позволит использовать многопоточность на уровне ОС для обработки запросов.

2. **Добавление Nginx в качестве обратного прокси:**
   Nginx используется для балансировки нагрузки между инстансами Gunicorn, также он может служить буфером для статических файлов и обеспечивать дополнительную безопасность. Nginx умеет эффективно распределять входящие соединения и имеет возможности кеширования.

3. **Использование асинхронного сервера как uvicorn с FastAPI или Starlette:**
   Это современные асинхронные фреймворки, которые позволяют писать асинхронные приложения на Python. Они могут улучшить пропускную способность приложения, особенно в I/O-высоконагруженных ситуациях. Flask-подобные приложения можно реорганизовать для использования с этими фреймворками, хотя это потребует некоторой переработки кода.

4. **Распределение вычислительных задач:**
   Чтобы избежать блокировки основного процесса сервера, тяжёлые вычислительные задачи можно выносить за пределы основного потока приложения. Используйте фоновые задачи с Redis и Celery для асинхронного выполнения этих задач.

Для решения проблемы с websocket'ами при масштабировании с помощью Nginx, убедитесь, что вы используете sticky sessions (сессии привязки к серверу), чтобы запросы от одного пользователя всегда направлялись к тому же серверу. Это важно, потому что веб-сокеты требуют установления постоянного соединения между клиентом и сервером. В Nginx конфигурации это можно реализовать через модуль ip_hash:

```nginx
upstream myapp {
    ip_hash;
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    # ... и другие сервера
}

server {
    location /socket.io {
        proxy_pass http://myapp;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        # ... остальные заголовки
    }
}
```

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

Использовать Celery для выноса тяжелых задач в очередь, без блокирования основного потока Flask.
Обычно, для CPU-bound задач подходит их вынесение в ОТДЕЛЬНЫЙ ПРОЦЕСС. 
В питоне это через multiprocessing пакет (встроенный) можно сделать.
Похожие вопросы