FastAPI 生产环境如何部署?需要注意哪些性能和稳定性问题?
简化版
FastAPI 生产环境通常用 Uvicorn 作为 ASGI server,也可以用 Gunicorn 管理多个 Uvicorn worker,前面再接 Nginx 或网关。部署时要关注 worker 数量、超时、连接池、日志、健康检查、反向代理头、异步阻塞、优雅退出和安全配置。
详细版
常见部署结构:
Client -> Nginx / LB -> Gunicorn + UvicornWorker 或 Uvicorn workers -> FastAPI -> DB/Redis
关键注意点:
- 不要在生产直接使用开发模式;
- 根据 CPU、I/O、内存设置 worker 数量;
- 异步接口内部不要调用阻塞代码;
- 数据库连接池要结合 worker 数量配置;
- 加健康检查接口;
- 配置日志、指标、链路追踪;
- 设置请求超时、上传大小限制、CORS、HTTPS;
- behind proxy 时正确处理 forwarded headers;
- 用 lifespan 做启动初始化和优雅关闭。
部署不是只把服务跑起来,而是让它能稳定、可观测、可恢复。
完整版教学
一、FastAPI 生产部署的基本结构
FastAPI 是 ASGI 应用,需要 ASGI 服务器运行。最常见的是 Uvicorn。简单启动命令类似:
uvicorn app.main:app --host 0.0.0.0 --port 8000
生产环境中,通常还会在前面放 Nginx、云负载均衡或 API 网关,负责 HTTPS、反向代理、限流、静态资源、请求大小限制等。
多进程部署可以用 Uvicorn 自带 workers:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
也可以用 Gunicorn 管理 Uvicorn worker:
gunicorn app.main:app -k uvicorn.workers.UvicornWorker -w 4
不同部署方式各有习惯和版本差异,核心是:FastAPI 需要 ASGI server,生产环境要考虑多进程、代理、日志、健康检查和优雅退出。
二、worker 数量怎么考虑
worker 数量不是越多越好。worker 多可以利用多核 CPU,也能提高隔离性:某个 worker 阻塞或崩溃,不一定影响全部请求。
但 worker 多也会增加内存占用。每个 worker 是独立进程,会加载一份应用、模型、连接池。如果应用加载了大模型,4 个 worker 可能就是 4 份模型内存。
数据库连接池也会被放大。假设每个 worker 连接池最大 20,4 个 worker 就可能产生 80 个数据库连接。很多生产事故不是 API 代码错,而是 worker 和连接池乘起来超过数据库上限。
因此设置 worker 要综合 CPU 核数、请求类型、内存、数据库连接数和模型大小。
三、异步阻塞是 FastAPI 生产性能大坑
FastAPI 支持异步,但生产中常见问题是 async def 里调用同步阻塞库:
@app.get("/bad")
async def bad():
resp = requests.get("https://example.com")
return resp.json()
这个接口看起来是异步,实际上 requests.get() 会阻塞事件循环。正确做法是使用异步客户端:
async with httpx.AsyncClient() as client:
resp = await client.get("https://example.com")
数据库也是一样。同步 ORM 可以放在普通 def 路由或线程池里,全链路异步则要使用异步驱动和 AsyncSession。
四、反向代理和 forwarded headers
生产环境常见链路是客户端先到 Nginx 或负载均衡,再转发给 FastAPI。此时 FastAPI 看到的客户端 IP、协议可能是代理的地址和 HTTP,而不是用户真实来源和 HTTPS。
如果应用需要生成绝对 URL、记录真实 IP、判断是否 HTTPS,就要正确配置代理头,例如 X-Forwarded-For、X-Forwarded-Proto。同时必须只信任可信代理,不能盲目信任外部用户伪造的 forwarded headers。
Nginx 还要处理 WebSocket upgrade、流式响应缓冲、上传大小、超时等配置。特别是 WebSocket 和 SSE,如果代理缓冲或超时设置不当,会出现本地正常、线上断流的问题。
五、健康检查和优雅退出
生产服务需要健康检查接口,例如:
@app.get("/health")
def health():
return {"status": "ok"}
更完善的健康检查可以区分 liveness 和 readiness。liveness 表示进程还活着,readiness 表示应用已经准备好接流量,比如数据库连接可用、模型加载完成。
优雅退出也很重要。服务发布或容器停止时,应停止接新请求,等待已有请求处理完成,再关闭连接池和后台任务。FastAPI 的 lifespan 可以用于关闭阶段释放资源。
六、日志、指标和追踪
生产环境必须可观测。至少要有结构化日志、错误日志、访问日志。更进一步可以接入 Prometheus 指标、OpenTelemetry 链路追踪、APM 平台。
常见指标包括请求量、响应时间、错误率、数据库连接池使用情况、外部依赖耗时、worker 重启次数。没有这些信息,线上慢请求和偶发错误很难定位。
Trace ID 很实用。可以在中间件里为每个请求生成 trace id,写入日志并返回响应头。用户反馈问题时,拿 trace id 可以串起整条链路。
七、安全和稳定性配置
生产环境不要开启调试模式。CORS 要按实际前端域名配置,不要为了省事长期允许所有来源和所有凭证。
请求体大小、上传文件大小、接口超时、慢请求保护都要配置。否则一个大文件或慢连接就可能占用大量资源。
敏感配置通过环境变量或密钥管理系统注入,不要提交到代码仓库。数据库密码、JWT 密钥、第三方 API Key 都属于敏感信息。
八、常见误区与追问
| 部署项 | 面试要点 | 常见风险 |
|---|---|---|
| Worker | 结合 CPU、内存、I/O、连接池配置 | worker 过多导致内存和 DB 连接爆掉 |
| 反向代理 | HTTPS、超时、上传大小、WebSocket、forwarded headers | 真实 IP 和协议识别错误 |
| 可观测性 | 日志、指标、Trace ID、健康检查 | 出问题只能靠猜 |
2 台机器 * 每台 4 worker * 每 worker pool_size=10
仅 API 服务就可能占用 80 个数据库连接。
再加 max_overflow=10 时,峰值可能到 160 个连接。
易错点:生产部署不是把 Uvicorn 跑起来,而是让服务在流量、故障、发布和排查时都可控。
- 误区:生产环境直接用开发启动方式就够了。 生产需要多 worker、反向代理、日志、健康检查、超时、优雅退出和安全配置。
- 误区:worker 越多吞吐越高。 worker 会复制应用内存、模型和连接池,过多可能先压垮内存或数据库连接数。
- 误区:异步框架可以忽略阻塞调用。
requests、同步 ORM、CPU 大循环仍会拖慢事件循环或耗尽线程池。 - 追问:为什么要区分 liveness 和 readiness? liveness 用于判断进程是否需要重启,readiness 用于判断是否已经完成初始化、可以接收流量。
- 追问:反向代理头为什么不能盲目信任? 外部用户可以伪造
X-Forwarded-For,只有来自可信代理的转发头才应该被应用采信。 - 追问:线上慢请求怎么定位? 需要访问日志、业务日志、Trace ID、外部依赖耗时、数据库慢查询和指标监控共同定位,而不是只看接口代码。
九、加强记忆
记 FastAPI 生产部署,不是只会写 uvicorn main:app。完整答案要覆盖 ASGI server、worker、反向代理、连接池、异步阻塞、健康检查、优雅退出、日志指标和安全配置。真正的生产稳定性来自这些工程细节。