Вопрос проверяет понимание того, как Python-приложения обслуживают HTTP-трафик в production и зачем нужен отдельный сервер процессов.
Gunicorn — это сервер приложений для Python, который запускает ваше веб-приложение (обычно WSGI-приложение) и управляет несколькими рабочими процессами. Он принимает входящие соединения, распределяет запросы по worker’ам и перезапускает их при сбоях. Gunicorn часто ставят за reverse proxy (например, Nginx). Он нужен, чтобы приложение могло обслуживать много запросов и работать стабильнее, чем встроенный dev-сервер.
Gunicorn (Green Unicorn) — это production-сервер для запуска Python веб-приложений. Его ключевая роль — не “писать бизнес-логику”, а надёжно принимать запросы и отдавать их вашему приложению в нескольких процессах (и иногда потоках), обеспечивая параллельность и устойчивость.
Частая схема:
Клиент (браузер/мобильное приложение)
Reverse proxy (часто Nginx)
завершает TLS (HTTPS)
умеет раздавать статику
может буферизовать запросы
Gunicorn
держит пул worker’ов
проксирует запросы в приложение
Приложение (Django/Flask и др.)
выполняет бизнес-логику
ходит в БД/кэш/очередь
Основная идея: один процесс Python неэффективен для параллельной обработки большого числа запросов. Поэтому Gunicorn запускает несколько worker-процессов.
Master process
стартует и контролирует worker’ов
перезапускает worker, если он упал
может делать “graceful reload” конфигурации
Worker processes
реально выполняют обработку запросов
каждый worker обрабатывает запросы независимо
если один worker завис/упал, остальные продолжают работать
Sync workers (по умолчанию)
один worker обрабатывает один запрос за раз
параллельность достигается количеством процессов
хорошо подходит для CPU/IO-смешанных задач, если запросы не “висят” очень долго
Thread workers (gthread)
внутри worker есть несколько потоков
полезно, если много I/O и хочется меньше процессов
Async workers (gevent/eventlet)
рассчитаны на большое количество одновременных соединений
требуют определённой модели кода и аккуратности с блокирующими вызовами
Встроенные dev-серверы (например, Flask/Django) предназначены для разработки:
слабее по устойчивости
не рассчитаны на высокую нагрузку
часто однопроцессные
Gunicorn даёт:
управление worker’ами
перезапуск при падениях
нормальную модель запуска в production
Для WSGI-приложения (например, Django):
gunicorn myproject.wsgi:application --workers 4 --bind 0.0.0.0:8000
Для Flask-приложения:
gunicorn app:app --workers 4 --bind 0.0.0.0:8000
Где:
--workers 4 — количество процессов
--bind — адрес и порт
На практике ориентируются на:
количество CPU
характер нагрузки (CPU-bound или I/O-bound)
лимиты памяти
Часто используют эмпирическое правило (как стартовую точку):
workers = 2 * CPU + 1
Но это не “закон”, потому что:
если запросы тяжёлые по памяти, много worker’ов приведёт к OOM
если запросы mostly I/O, можно использовать threads или async
Таймауты
защищают от “вечных” запросов
пример: --timeout 30
Лимиты на запросы
перезапуск worker после N запросов помогает лечить утечки памяти
пример: --max-requests 1000 --max-requests-jitter 100
Логи
доступы и ошибки важны для диагностики
обычно логирование централизуют (stdout/stderr в контейнере)
Gunicorn используют для запуска Python веб-приложений в production, потому что он обеспечивает параллельность через worker-процессы, устойчивость через контроль и перезапуск, и удобную интеграцию с reverse proxy. Он особенно полезен, когда нужно обслуживать много запросов и не зависеть от ограничений dev-сервера.