Если у вас Python‑приложение и на VDS пора выходить в прод, выбор между uWSGI и Gunicorn возникает почти всегда. Оба сервера реализуют WSGI, оба давно в продакшене, но различаются философией, моделью воркеров, набором возможностей и ценой в администрировании. Ниже — практичное сравнение для админов и девопсов: как повлиять на производительность и стабильно жить под Nginx и systemd.
Кратко: когда какой сервер
Сразу ответ для тех, кто спешит:
- Gunicorn — минимализм и предсказуемость. Отличный выбор для Django/Flask, когда нужны простые синхронные воркеры, быстрая интеграция с Nginx и прозрачные перезапуски. Также Gunicorn часто используют как менеджер для ASGI через воркеры Uvicorn.
- uWSGI — «швейцарский нож». Море настроек, Emperor/Vassals для множественных приложений, offload, spooler, «cheaper»‑алгоритмы экономии RAM. Требует дисциплины в конфигурации, но раскрывается на плотных VDS со множеством сервисов.
Для ASGI‑приложений (FastAPI/Starlette) обычно берут Uvicorn, нередко в связке с Gunicorn как процесс‑менеджером. uWSGI — про WSGI в первую очередь.
Архитектура и модель воркеров
Gunicorn
Gunicorn запускает мастер‑процесс и пул воркеров. По умолчанию — синхронные воркеры на основе prefork. Есть альтернативы: gevent, eventlet, gthread, а для ASGI — воркеры Uvicorn. Конфигурация через флаги командной строки или Python‑конфиг. Философия: минимально необходимый набор, остальное — через воркеры и экосистему.
uWSGI
uWSGI — это не только сервер приложений, но и обширная платформа (плагины, режим Emperor/Vassals, internal routing, offload threads, spooler для задач и т. д.). Конфиги в INI/YAML‑стиле, множество опций, несколько способов двухфазного перезапуска. Есть встроенные механики снижения потребления памяти при простое (семейство опций cheaper).

Производительность: где узкие места
Латентность и RPS упираются в несколько факторов:
- тип воркеров (синхронные vs асинхронные),
- число воркеров и потоков,
- Copy‑on‑write и
preload_app, - стоимость сериализации ответа/шаблонов,
- проксирование (Nginx), сокеты (UNIX vs TCP),
- таймауты и очереди (listen backlog).
На CPU‑ограниченных VDS синхронные воркеры показывают предсказуемую латентность при CPU‑bound задачах. Для I/O‑bound чаще выигрывают gthread или gevent/Uvicorn‑воркеры (Gunicorn) либо асинхронная модель на стороне приложения. uWSGI предоставляет собственные твики, но выигрыш зависит от конкретной нагрузки.
UNIX‑сокет или TCP
Если Nginx и приложение на той же машине, выбирайте UNIX‑сокет: меньше накладных расходов и нет TCP‑стека между процессами. Следите за правами на сокет и директорией, где он создаётся.
Copy‑on‑write и preload
И Gunicorn, и uWSGI умеют предварительно загружать приложение в мастере (Gunicorn: --preload, uWSGI: lazy-apps и родственные). Это экономит RAM за счёт copy‑on‑write, ускоряет форк воркеров и даёт стабильную латентность на старте воркера. Не забывайте, что любые записи в глобальные структуры после preload ломают выгоду от CoW.
Конфигурация: насколько сложна
Gunicorn: минимум, который работает
Базовый старт для Django/Flask — одна строка, параметры легко вынести в systemd‑юнит. Конфигурационный файл в Python позволяет держать все опции рядом с кодом.
uWSGI: мощно, но многословно
uWSGI предлагает десятки ключей. Это плюс, когда нужно тонко управлять воркерами, проводить перезапуски без потери соединений, запускать много приложений через Emperor. Но из‑за широты опций выше риск случайно ввести противоречивые настройки. Рекомендуется формализовать «профили» под типовой стек (Django sync, Flask + threads и т. п.).
Интеграция с Nginx
Типовой паттерн: Nginx принимает внешние соединения, терминирует TLS, кэширует статику и проксирует на Gunicorn/uWSGI по UNIX‑сокету. Убедитесь, что согласованы client_max_body_size, proxy_read_timeout и таймауты приложения, иначе получите 499/504 под нагрузкой. Если параллельно переводите сайт на HTTPS и HSTS, пригодится наш разбор по переносу домена и политикам безопасности — смотрите материал «Перенос домена с 301 и HSTS» (как мигрировать и включить HSTS). Для выпуска и установки сертификатов используйте SSL-сертификаты.
# Фрагмент server для Nginx (проксирование к UNIX-сокету)
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://unix:/run/app.sock;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
Если используете uWSGI‑протокол, возможен uwsgi_pass, но HTTP через proxy_pass универсальнее и проще для отладки.
Выбор типов воркеров и формул
- Синхронные (по умолчанию в Gunicorn, аналог в uWSGI): хороши для CPU‑bound и простых I/O, предсказуемая латентность.
gthread(Gunicorn) и потоки в uWSGI: помогают при умеренной I/O‑нагрузке с блокирующими вызовами.gevent/eventlet(Gunicorn) или асинхронные режимы в uWSGI: уместны, если библиотека совместима с monkey patching и нагрузка преимущественно I/O.
Базовая оценка числа воркеров для синхронных процессов: workers = 2 × CPU + 1. Для потоков — меньше воркеров, больше потоков. Для Uvicorn‑воркеров под ASGI — отталкивайтесь от I/O, часто 1–2 воркера на ядро достаточно.
Перезапуски без простоя
Оба сервера поддерживают graceful‑перезапуск: мастер перестаёт принимать новые коннекты, ждёт завершения активных запросов и перезапускает воркеры. Если готовите релиз с минимальным простоем, пригодится пошаговый гид про миграцию без даунтайма — см. материал «Миграция проекта без простоя» (чек‑лист с этапами).
- Gunicorn: сигнал
HUPперечитывает конфиг,USR2— zero‑downtime перезапуск с новым мастером. - uWSGI: разные стратегии через
touch-reload,die-on-term, двойной мастер и др. Emperor даёт перезапуск отдельных «вассалов».
Логирование и метрики
Оба сервера пишут access/error‑логи. Для метрик популярны statsd/Prometheus‑сборщики через сторонние экспортеры или плагины. Главное — не забывать про ротацию логов и log-level на проде, чтобы не тратить CPU и диск на болтливость.
Безопасность и изоляция
- Запускайте под отдельным пользователем, не под root.
- UNIX‑сокет в каталоге с ограниченными правами, корректные
umaskи владельцы. - Ограничьте
nofileи память через systemd или cgroups. - Не держите отладку и подробные traceback в продакшене.
Примеры конфигураций
Gunicorn + systemd
[Unit]
Description=Gunicorn for myapp
After=network.target
[Service]
User=app
Group=app
WorkingDirectory=/srv/myapp
Environment="PATH=/srv/myapp/venv/bin"
ExecStart=/srv/myapp/venv/bin/gunicorn wsgi:app --workers 4 --bind unix:/run/myapp.sock --timeout 60 --graceful-timeout 60 --access-logfile - --error-logfile -
RuntimeDirectory=myapp
RuntimeDirectoryMode=0750
KillMode=mixed
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Проверьте, что директория /run создаётся systemd (через RuntimeDirectory), иначе сокет некуда положить. Для Python‑конфига Gunicorn можно вынести опции из строки ExecStart, чтобы не разрасталась. Если управляете сервером через панель, сравнение актуальных панелей для админов — в статье «Сравнение панелей для VDS» (что выбрать в 2025).
uWSGI Emperor + vassal
# /etc/systemd/system/uwsgi-emperor.service
[Unit]
Description=uWSGI Emperor
After=network.target
[Service]
User=uwsgi
Group=uwsgi
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --die-on-term --log-format "%(method) %(uri) %(status) %(msecs)ms"
Restart=on-failure
KillMode=mixed
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
# /etc/uwsgi/vassals/myapp.ini
[uwsgi]
chdir = /srv/myapp
module = wsgi:app
master = true
processes = 4
threads = 1
socket = /run/myapp.sock
chmod-socket = 660
vacuum = true
die-on-term = true
harakiri = 60
buffer-size = 65535
max-requests = 5000
reload-on-as = 512
reload-on-rss = 384
# Для graceful-перезагрузки достаточно тронуть файл
touch-reload = /srv/myapp/reload
# Экономия памяти при простое
cheaper = 2
cheaper-initial = 2
cheaper-step = 1
# Логи
disable-logging = false
Режим Emperor удобен, когда на одном VDS несколько сервисов. Для одиночного приложения можно обойтись без Emperor и поднять единичный service‑юнит с конкретным --ini.

Методика мини‑бенчмарка
Чтобы не спорить «на вкус», сравните у себя. Простейший план:
- Отключите все фоновые джобы, чтобы не шумели на CPU и диске.
- Поднимите Nginx + сервер приложений на одном VDS.
- Замерьте четыре режима: Gunicorn sync, Gunicorn gthread, uWSGI processes+threads, uWSGI только процессы.
- Снимите метрики RPS и p95/p99 lat, CPU iowait, ошибки 5xx/499.
# Пример однопоточного обстрела
wrk -t4 -c128 -d60s http://127.0.0.1/
# Наблюдать ресурсы
pidstat -ruhl 1
ss -lntp
Честный тест требует одинакового числа воркеров и идентичной логики приложения. Если есть тяжёлый шаблонизатор, вынесите рендер в шаблон с прогревом, чтобы уменьшить холодные эффекты.
Таймауты, очереди и лимиты
- Таймаут запроса: в Gunicorn
--timeout, в uWSGIharakiri. Должны быть согласованы сproxy_read_timeoutв Nginx. - Очередь сокета: увеличьте listen backlog (uWSGI:
listen, Gunicorn уважает системныйsomaxconn), чтобы не терять пики. - Размер буфера: uWSGI
buffer-sizeдля длинных заголовков, иначе 502. В Nginx настройтеlarge_client_header_buffers. - Ограничения файлов: увеличьте
LimitNOFILEи системныйfs.file-max, если много соединений.
Память и Copy‑on‑write
Оцените базовую RAM на воркер: при preload у Gunicorn на Python 3.11 типично 20–60 МБ на воркер для простого Flask/Django. В uWSGI — сопоставимо, но cheaper уменьшает общее число процессов при простое. Следите за метрикой RSS на воркерах и перезапускайте при утечках (max-requests у обоих серверов помогает ограничить рост).
Отладка и диагностика
- Проверьте права сокета и каталога. Частая причина 502 — Nginx не может открыть UNIX‑сокет.
- Смотрите error‑логи сервера приложений и Nginx: несогласованные таймауты и размер заголовков видны сразу.
- Включите access‑лог с латентностью в мс, чтобы ловить хвосты p95/p99.
- Проверяйте GC‑паузы и кумулятивное время в логике приложения — сервер приложений не лечит медленный код.
Сравнение по критериям
- Простота: Gunicorn выигрывает. Один бинарь, понятные флаги, прогнозируемое поведение.
- Гибкость: uWSGI впереди — Emperor, offload, spooler, тонкая настройка маршрутизации.
- ASGI: Gunicorn как менеджер для Uvicorn популярен; uWSGI ориентирован на WSGI.
- Память: сопоставимо, но uWSGI «cheaper» удобен на VDS со сменной нагрузкой.
- Перезапуски: оба умеют graceful и zero‑downtime, у uWSGI больше стратегий.
- Кривая обучения: у uWSGI выше — много опций и нюансов совместимости.
Практические пресеты
Django/Flask, синхронно, 2 vCPU
- Gunicorn: 5 воркеров (
2 × 2 + 1),--timeout 60, UNIX‑сокет. - uWSGI:
processes = 5,threads = 1,harakiri = 60,cheaper = 2.
I/O‑heavy, блокирующие библиотеки
- Gunicorn: 2 воркера на vCPU,
--worker-class gthread,--threads 8. - uWSGI: меньше процессов, больше
threads, проверьте GIL‑сценарии.
ASGI (FastAPI/Starlette)
- Gunicorn с воркерами Uvicorn: 1–2 воркера на ядро,
--worker-class uvicorn.workers.UvicornWorker, тюньте--graceful-timeout.
Частые ошибки и как их избежать
- Несогласованные таймауты: 504 в Nginx при долгом рендере страниц. Согласуйте
proxy_read_timeoutиharakiri/--timeout. - Перегрузка очереди: при пиках теряются соединения. Увеличьте backlog и количество воркеров, закупорьте «тяжёлые» пути кэшем.
- Логи душат диск: на пике JSON‑лог в учётной системе может съесть CPU. Уменьшайте детализацию, включайте ротацию.
- Память утекает: включите
max-requestsи отслеживайте RSS. Не лечит первопричину, но стабилизирует сервис. - Неправильные права на сокет: Nginx от имени
www-dataне читает сокет приложения — настройтеchmod-socketи группу.
Итоговые рекомендации
Если нужен быстрый и понятный старт, минимум движущихся частей и хорошие дефолты — выбирайте Gunicorn. Он отлично дружит с Nginx и systemd, предсказуем в поведении и логировании, легко масштабируется по воркерам. Если у вас сложный многосервисный хост, важна экономия памяти на простое, нужны встроенные механики вроде Emperor, cheaper, spooler и тонкая маршрутизация — присмотритесь к uWSGI. По чистой производительности на равных настройках разницы часто нет, выигрывает тот, кто точнее настроен под вашу нагрузку.
Не поленитесь провести локальный бенч и зафиксировать пресет параметров для своего профиля трафика. Это окупается: предсказуемая латентность, понятные перезапуски, отсутствие 502/504 в пике и экономия памяти на VDS.


