Разработка минимального FastAPI-сервиса
Уроки курсаРазработка минимального FastAPI-сервиса
6. Флаг --reload в продакшене: тихая проблема
При разработке FastAPI-сервиса запускают uvicorn с флагом --reload:
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
Это удобно: сохранил файл — сервер перезапустился автоматически. Но именно здесь кроется ловушка, которая не даёт о себе знать до первого нагрузочного теста в продакшене. --reload запускает watchdog-процесс, который следит за изменениями файлов и перезапускает uvicorn при каждом обнаруженном изменении. В продакшене нет разработчика, который редактирует файлы, но watchdog всё равно работает и потребляет ресурсы. Хуже того: если файловая система ведёт себя нестандартно (например, в контейнере с примонтированными volume), watchdog может срабатывать непредсказуемо и перезапускать сервер под нагрузкой — прямо в момент обработки запросов. Вторая проблема: --reload запускает приложение в однопоточном режиме, без возможности использовать несколько воркеров. Флаг --workers N и --reload несовместимы — uvicorn просто проигнорирует --workers, если указан --reload. Правильный запуск в продакшене:
### ❌ Разработка — не для продакшена uvicorn main:app --host 0.0.0.0 --port 8000 --reload ### ✅ Продакшен — несколько воркеров, без reload uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
Число воркеров обычно выбирают по формуле 2 * CPU_cores + 1, но для ML-сервиса стоит учитывать, что каждый воркер держит свою копию модели в памяти. Если model.pkl весит 200 МБ, четыре воркера займут ~800 МБ только под модель — это нужно закладывать в требования к инфраструктуре. Ещё один продакшен-вариант — запускать uvicorn через Gunicorn с uvicorn-воркерами:
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
Gunicorn в этом случае управляет воркерами, следит за их здоровьем и перезапускает упавшие процессы — это более надёжная схема для долгоживущего сервиса, чем голый uvicorn.
