Uvicorn的--workers不适用于生产环境,因其spawn启动导致高内存占用、无优雅关闭、无健康检查、不支持动态扩缩容,且容器中易被误杀;应改用Gunicorn+UvicornWorker组合,并配置超时、连接队列等参数。

别用 uvicorn main:app --reload 上生产,它会监听文件、单进程、无超时控制,线上一跑就卡死或重启中断请求。
为什么不能直接用 --workers 启动多进程?
Uvicorn 的 --workers 确实能开多个子进程,但它用的是 spawn 方式启动,每个 worker 都要重新导入整个应用和依赖,内存占用高、冷启动慢;更重要的是——它不支持优雅关闭、不支持动态扩缩容、没有健康检查和进程自动拉起机制。
- 主进程只做简单监控,worker 崩溃后虽会重启,但没重试退避、没日志聚合
- 无法响应
SIGHUP实现零停机 reload(除非你手动发信号并写 wrapper 脚本) - 在容器环境里,
--workers启动的进程树容易被 PID 1 管理器误判为“孤儿进程”而 kill 掉
用 Gunicorn + UvicornWorker 是更稳的选择
让 Gunicorn 做进程管理,Uvicorn 做 ASGI 协议处理,分工明确。注意:不是所有版本都默认支持 uvicorn.workers.UvicornWorker —— 它已在较新 uvicorn 版本中弃用,必须单独装 uvicorn-worker 包:
pip install uvicorn-worker
然后启动:
Uvicorn 0.52.1 是 Python ASGI Web 服务器,提供异步应用服务及 WebSocket 支持,常用于 FastAPI、Starlette 等应用的开发和部署。本下载为官方 PyPI 通用 wheel 包,可使用 pip 安装,并由包管理器处理所需依赖。
gunicorn -w 4 -k uvicorn_worker.UvicornWorker main:app
-
-w 4表示 4 个 worker 进程,建议设为cpu_count * 2 + 1,I/O 密集型可略高 - 不要加
--preload,否则所有 worker 共享同一份全局状态,可能引发并发 bug - 若用
uvloop,确保已安装uvicorn[standard],UvicornWorker 会自动启用
必须改掉的默认参数:timeout、backlog、limit-concurrency
Uvicorn 默认 timeout=60,对数据库慢查询或外部 API 调用极不友好,线上应设为业务最大容忍延迟(比如 120 或 300)。同时要调大连接队列:
-
--timeout 120:避免长请求被无差别 kill -
--backlog 2048:Linuxlisten()系统调用的等待队列长度,防止 SYN 包丢弃 -
--limit-concurrency 5000:限制每个 worker 并发处理请求数,防止单个 worker 被拖垮影响全局
这些参数在 Gunicorn 模式下要通过配置文件传给 UvicornWorker,例如 gunicorn.conf.py 中加:
raw_env = ["UVICORN_TIMEOUT=120", "UVICORN_BACKLOG=2048", "UVICORN_LIMIT_CONCURRENCY=5000"]
容器里运行时最容易漏掉的三件事
Docker 镜像里跑 Uvicorn,光改命令不够,还得管用户、信号、日志流向:
- 必须用非 root 用户运行:
RUN groupadd -r appuser && useradd -r -g appuser appuser+USER appuser - 显式设置
--host 0.0.0.0和--port 8000,别依赖环境变量,Docker network 模式下127.0.0.1绑定等于没绑 - 禁用
--reload,哪怕你在docker-compose.yml里写了UVICORN_RELOAD=true,也要确认基础镜像没带开发依赖(如watchfiles),否则会偷偷启动监听
最后提醒一句:Nginx 反向代理不是可选项,是必选项。Uvicorn 不处理静态文件、不终止 SSL、不抗慢客户端,这些全得靠 Nginx 拦在前面。直接暴露 Uvicorn 端口到公网,等于把 ASGI 内部状态裸奔出去。

















