首页
/ FastAPI 部署进阶:使用 Uvicorn Workers 实现多进程复制

FastAPI 部署进阶:使用 Uvicorn Workers 实现多进程复制

2026-09-07 14:13:18作者:董灵辛Dennis

生产环境中的 FastAPI 应用往往不能只跑在单个进程上——单进程只能使用一个 CPU 核心、能承载的请求量有限。这篇指南基于 FastAPI 官方文档中的「Server Workers - Uvicorn with Workers」章节(参见 英文原文西班牙语译文),系统讲解如何通过一行 --workers 命令让 Uvicorn 派生多个 Worker 进程,从而并行利用多核 CPU、复制进程以提升吞吐,并说明它在整套部署概念清单中究竟解决了什么、还遗留了什么。

读完本文,你将掌握两种启动多 Worker 的方式(fastapi runuvicorn 命令行)、理解父子进程 PID 的日志含义,并能正确判断在 Kubernetes / Docker 场景下「该不该用 Workers」。

回到部署概念清单:Workers 解决的是哪一环

在深入命令之前,需要把部署问题放回更大的框架中。正如 部署概念 一章所归纳的,部署任何 Web API 都要考虑六个核心概念:

  • 安全(HTTPS)
  • 开机自启(Running on startup)
  • 重启(Restarts)
  • 复制(Replication,即正在运行的进程数量)
  • 内存(Memory)
  • 启动前的准备步骤(Previous steps before starting)

在官方文档的所有教程里,无论是用 fastapi 命令还是直接跑 Uvicorn,默认都只是运行 一个单独的进程。这在本地开发时没问题;但到了部署阶段,为了让一个 IP 与端口上的应用能够同时服务更多请求、把 CPU 的多个核心都用起来,你需要引入 进程复制——也就是本文的核心:多个 Worker 进程

官方原文档在此处特别提醒:如果你在使用 Docker、Kubernetes 这类容器方案,那么下一章 FastAPI in Containers - Docker 才是重点;尤其是跑在 Kubernetes 上时,通常 建议开 Workers,而是「每个容器跑单个 Uvicorn 进程」,复制交给容器编排层去完成。本文讨论的是「自己搭一套进程管理系统」的场景。

为什么需要多个进程:单进程的天然瓶颈

要理解多 Worker 的价值,先要回到操作系统层面的两个事实(详见 部署概念 · 复制与进程):

  1. 进程是独立的执行单元。一个 FastAPI 应用在一个进程里运行,可以通过异步并发服务多个客户端,但计算仍然只发生在一个 CPU 核心上;
  2. 同一时刻,只能有一个进程监听某个「IP + 端口」组合。因此要实现多进程并行,必须有一个 进程管理器(parent process / process manager) 独占监听端口,再把进来的通信分发给它启动的各个 Worker 进程——这正是 --workers 做的事情。

--workers 启动多个 Worker

核心命令只有一个新选项:--workers。它可以同时出现在 fastapiuvicorn 两个命令行入口上。

方式一:使用 fastapi 命令

如果你安装的是 fastapi[standard](其中包含 fastapi-cli),就可以直接使用仓库内置的 fastapi 命令行(入口见 fastapi/cli.pyfastapi/main.py):

$ fastapi run --workers 4 main.py

   FastAPI   Starting production server 🚀
             Searching for package file structure from directories with
             __init__.py files
             Importing from /home/user/code/awesomeapp

   module    🐍 main.py
   code      Importing the FastAPI app object from the module with the
             following code:

             from main import app

   app       Using import string: main:app

   server    Server started at http://0.0.0.0:8000
   server    Documentation at http://0.0.0.0:8000/docs

             Logs:

   INFO      Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
   INFO      Started parent process [27365]
   INFO      Started server process [27368]
   INFO      Started server process [27369]
   INFO      Started server process [27370]
   INFO      Started server process [27367]
   INFO      Waiting for application startup.
   INFO      Waiting for application startup.
   INFO      Waiting for application startup.
   INFO      Waiting for application startup.
   INFO      Application startup complete.
   INFO      Application startup complete.
   INFO      Application startup complete.
   INFO      Application startup complete.

方式二:直接使用 uvicorn 命令

如果你更喜欢绕开 fastapi 包装、直接驱动 Uvicorn,可以这样写(uv run 表示在项目虚拟环境中执行):

$ uv run uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
INFO:     Started parent process [27365]
INFO:     Started server process [27368]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Started server process [27369]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Started server process [27370]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Started server process [27367]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

两种命令唯一的区别是入口:fastapi 会先从 main.py 中解析出 FastAPI 应用对象(日志中的 Using import string: main:app),再把它交给 Uvicorn;而 uvicorn 则直接接收 main:app 这样的 import string。两者的底层 worker 机制完全一致。

读懂日志里的 PID 与启动时序

注意看日志,你会看到两类 PID(进程 ID):

  • Started parent process [27365] —— 这个父进程就是 进程管理器(process manager),它负责独占监听 IP:端口,并把请求分发到下面的 worker;
  • 4 条 Started server process [...]27368273692737027367)—— 对应 --workers 4 启动的 4 个真正的 worker 进程,你的 FastAPI 应用代码运行在它们内部。

还有一个容易被忽略的细节:启动日志中出现了 4 次 Waiting for application startup. 与 4 次 Application startup complete.——这正说明 FastAPI 的 startup 事件(lifespan/startup handler)会在每一个 worker 进程里各自执行一遍。如果你的启动逻辑里加载了大对象(例如机器学习模型),请记住:每个 worker 都会各自在内存中加载一份(这一点下文「内存」小节还会展开)。

补充一个可执行性的前提:fastapi 命令并非 fastapi 库自带的唯一入口,它依赖可选的 fastapi-cliuvicorn[standard] 组件。在当前仓库的 pyproject.toml 中可以看到,standard 扩展分别声明了 fastapi-cli[standard] >=0.0.32uvicorn[standard] >=0.12.0 作为依赖,因此请通过 pip install "fastapi[standard]" 来安装以获得完整的命令行体验。

Workers 到底解决了部署清单里的哪几项?

回到开头那张「部署概念清单」,--workers 的定位非常明确:

  • 主要解决「复制(Replication)」:多个进程并行执行、共同分担请求,是它最核心的贡献;
  • 顺带解决一点「重启(Restarts)」:进程管理器会监督 worker 进程的状态,单个 worker 崩溃时能够被重新拉起;
  • 但其余概念它一概不管
部署概念 多 Worker 是否能解决 说明
安全 - HTTPS 仍需 TLS 终止代理(Traefik、Caddy、Nginx 等)处理证书与加密
开机自启(Running on startup) 仍需 systemd、Supervisor、Docker 等外部组件拉起进程
重启(Restarts) ⚠️ 部分 管理器可应对 worker 崩溃,但无法重启自身
复制(Replication) ✅ 主要目标 多个 worker 并行利用多核 CPU、服务更多请求
内存(Memory) ❌ 反而要注意 每个 worker 独立占用 RAM,复制等于成倍放大内存
启动前准备步骤(Previous steps) ❌ 需要单独设计 迁移等一次性步骤若被多个 worker 重复执行会产生冲突

内存的乘法效应:务必按 RAM 规划 worker 数量

多进程的优势是并行,代价则是 内存不共享。官方文档在 部署概念 中给出了一个非常直观的例子:如果你的代码在变量里加载了一个 1 GB 的机器学习模型,那么:

  • 1 个进程 → 至少消耗 1 GB RAM;
  • 4 个 worker → 每个都独立加载一份,总共消耗约 4 GB RAM。

若服务器总共只有 3 GB 内存却开了 4 个 worker,就会出现内存耗尽甚至崩溃。因此 worker 数量不能只盯着 CPU 核心数,还要用「单进程峰值内存 × worker 数 ≤ 可用 RAM」来校验。这同时对应概念章节里的「资源利用率」建议:既不要大量闲置浪费,也不要跑到 100% 顶着崩溃边缘,官方给出的经验区间是让资源利用率落在约 50%–90% 之间,并通过 htop 之类的工具观察进程的 CPU 与内存占用来调整。

启动前的准备步骤为何要格外小心

既然有多个 worker,那些「只需要执行一次」的前置步骤(例如数据库迁移)就成了隐患:如果让每个 worker 都各自跑一遍迁移,多个进程会并行重复操作甚至互相冲突。所以正确做法是:先用单独的一个进程执行这些一次性步骤,再启动多个 worker;或者干脆在你的部署方案里(比如 bash 启动脚本、Kubernetes Init Container)显式隔离「前置步骤」与「服务进程」。

容器与 Docker 的边界:Kubernetes 里通常不用 Workers

本文讨论的是「自己管理进程级复制」的路线:进程管理器监听端口、再拉起多个 Uvicorn worker,这一切发生在 同一台机器、同一个容器内部

而当你进入容器世界,路线会切换为 容器级复制

  • Docker / Docker Compose:用外部进程管理器(或容器自身的 restart 策略)处理自启与重启;
  • Kubernetes:由 Service / Ingress 在 IP 与端口上负责监听与负载分发,复制通过「多个 Pod、每个 Pod 内跑一个单进程 Uvicorn」实现——此时再在容器内开多个 worker 反而会让副本粒度变得混乱。

官方文档在下一章 FastAPI in Containers - Docker 中会手把手演示如何 从零构建自己的镜像,镜像内只运行一个单进程 Uvicorn,并把其余部署概念交给容器编排层解决——这正是官方推荐的生产路线。

小结

一句话总结本指南:在「自己搭建部署系统」的场景下,给 fastapi runuvicorn 加上 --workers N 选项,即可让一个父进程管理器派生出 N 个并行 worker 进程,从而利用多核 CPU、提升吞吐、应对更多请求

同时请记住它的边界:多 Worker 主要覆盖了部署清单里的 复制 与一小部分 重启;而 HTTPS、开机自启、内存规划、启动前的一次性步骤 仍需由你借助 systemd、Supervisor、Docker、Kubernetes 等外部组件补齐。下一步建议阅读 部署概念 补齐六个概念的底层直觉,再进入 Docker 容器部署 学习容器化方案——在那里你会看到编排工具如何用更简单的方式解决其余部署概念。

登录后查看全文
热门项目推荐
相关项目推荐