FastAPI入门:别再用Flask裸奔了,性能真的扛不住
去年十月,我从某大厂“优化”了出来。说白了就是被毕业了——双11前一周,HR约我喝咖啡,聊完我就抱着显示器站在陆家嘴的秋风里发呆。Gap这半年,没躺平,也没刷LeetCode到秃头,而是把之前在项目里一直想试但被PM追着改需求没空碰的新技术,挨个撸了一遍。FastAPI 就是其中之一。
为啥选它?因为在大厂那会儿,我们一个内部工具链 API 用 Flask 写的,QPS 超过 300 就开始抖,加机器都救不回来。运维老哥半夜三点打电话骂我:“你这接口是不是又在循环查数据库?Go 都跑得比你快!”
我当时真想回一句:“要不你来写?”
但转念一想,他说得对——Python Web 框架确实该升级了。
于是,在出租屋里(上海静安寺附近,月租八千五,肉疼),我泡了三天速溶咖啡,把 FastAPI 从 Hello World 搞到了能扛压测的水平。今天这篇,不讲官方文档复读机内容,就聊聊一个刚裸辞、正焦虑找工作的前大厂人,怎么用 FastAPI 把性能搞上去,顺便给想入坑后端的同学指条明路。
为什么是 FastAPI?不是 Go,也不是 Django?
先说结论:如果你是 Python 开发,要做高性能 API 服务,又不想直接切到 Go 的陡峭学习曲线,FastAPI 是目前最平衡的选择。
我知道有人又要杠:“Go 多快啊!协程、编译型、静态链接,吊打 Python。”
没错,Go 在系统级性能上确实碾压。但现实是:团队里十个 Python 工程师,九个不会 Go。强行切换语言,沟通成本、招聘成本、上线风险全拉满。而 FastAPI 借助 Pydantic + Starlette + asyncio,在保持 Python 开发体验的同时,把性能提到了接近 Go 的 60%-70%(实测数据后面放)。
更关键的是——它自带 OpenAPI 和自动文档。上次我们组新来的实习生,光看 /docs 页面就把前端对接搞定了,连 PM 都夸“这次接口写得像人话”。
快速上手?别急,先看架构设计
很多人一上来就 pip install fastapi,然后写个 @app.get("/"),跑起来觉得“哇好快”,结果一上生产就崩。为什么?因为没考虑综合性能瓶颈。
FastAPI 快,主要快在两个地方:
- 异步非阻塞 I/O(靠 Starlette 底层)
- 数据验证和序列化(靠 Pydantic,用 C 扩展加速)
但如果你在视图函数里写了个 time.sleep(5),或者循环查数据库十次,那再快的框架也救不了你。所以,算法和架构思维才是核心。
举个真实例子:我们之前有个“用户行为分析”接口,逻辑是——
- 传入 user_id
- 查 MySQL 用户基础信息
- 查 Redis 最近点击记录(100 条)
- 调另一个微服务拿推荐列表
- 合并数据返回
用 Flask 写的时候,同步调用,每个请求至少 800ms。后来我用 FastAPI 改造成 异步并发调用:
from fastapi import FastAPI
import httpx
import aioredis
import asyncio
app = FastAPI()
@app.get("/user/profile/{user_id}")
async def get_user_profile(user_id: int):
async with httpx.AsyncClient() as client:
# 并发发起多个异步请求
db_task = fetch_user_from_db(user_id)
redis_task = fetch_clicks_from_redis(user_id)
rec_task = client.get(f"http://rec-service/user/{user_id}")
user, clicks, rec_resp = await asyncio.gather(
db_task, redis_task, rec_task
)
return {
"user": user,
"clicks": clicks,
"recommendations": rec_resp.json()
}
注意:这里 fetch_user_from_db 也必须是异步的(比如用 aiomysql 或 SQLAlchemy 1.4+ async)。否则,整个 async 就形同虚设。
改完之后,P99 延迟从 1.2s 降到 320ms,QPS 从 280 提升到 1100+。运维老哥默默给我点了杯瑞幸。
性能对比:FastAPI vs Flask vs Go
为了验证效果,我在本地(MacBook Pro M1, 16GB)做了简单压测。测试接口:返回 {"hello": "world"}。
| 框架 | 并发 100 | QPS | P99 延迟 |
|---|---|---|---|
| Flask (sync) | 100 | ~420 | 240ms |
| FastAPI (async) | 100 | ~2100 | 48ms |
| Go (Gin) | 100 | ~8500 | 12ms |
测试工具:
wrk -t4 -c100 -d30s http://localhost:8000/
可以看到,FastAPI 虽然比不上 Go,但相比传统 Flask,性能提升 5 倍以上。而且代码复杂度几乎没增加。
但重点来了:实际业务中,瓶颈往往不在框架本身,而在数据库、缓存、网络 IO。所以别迷信“换框架就能起飞”,得做综合优化。
生产环境踩过的坑(血泪经验)
1. 别乱开 debug=True
上线第一天,我把本地配置原样复制到服务器,结果日志里全是 SQL 查询语句。更可怕的是,FastAPI 的自动 reload 功能在 debug 模式下会监听文件变化——生产环境 CPU 直接飙到 90%。
解决方案:严格区分环境变量
# main.py
import os
from fastapi import FastAPI
app = FastAPI(
debug=os.getenv("DEBUG", "false").lower() == "true",
docs_url="/docs" if os.getenv("ENV") != "prod" else None,
redoc_url=None,
)
线上关掉文档,安全又省资源。
2. 异步上下文管理器别乱用
有次我用 async with some_client() 包裹一个长耗时操作,结果连接池被占满,新请求直接 503。原因:异步客户端默认连接池大小有限(比如 httpx 是 10)。
解决方法:显式配置连接池
limits = httpx.Limits(max_connections=100, max_keepalive_connections=20)
client = httpx.AsyncClient(limits=limits, timeout=10.0)
或者,更好的做法是:全局复用一个 AsyncClient 实例(配合 lifespan 事件)。
3. Pydantic 模型别嵌套太深
Pydantic 快,是因为底层用了 C。但如果模型嵌套三层以上,带 validator,再配上大量字段,默认验证会变慢。
建议:
- 复杂校验放到业务逻辑层,别全塞进 Pydantic
- 用
@validator时注意性能,避免在 validator 里查数据库 - 对高频接口,可考虑关闭部分验证(
validate_assignment=False)
4. 静态文件别用 Uvicorn 直接 serve
FastAPI 内置的静态文件路由 (app.mount("/static", StaticFiles(...))) 仅适合开发。生产环境请用 Nginx。
否则,每次请求静态资源都要经过 Python 进程,白白浪费 CPU。
综合性能优化 checklist
作为一个被线上事故虐过的人,我整理了一份 FastAPI 服务上线前必查项:
- ✅ 使用
uvicorn启动时加--workers(根据 CPU 核数设,一般2 * cores + 1) - ✅ 数据库连接池配置合理(SQLAlchemy / asyncpg)
- ✅ 所有外部调用(HTTP、DB、Redis)必须异步
- ✅ 敏感接口加限流(可用
slowapi或中间件) - ✅ 日志结构化(用
structlog),方便 ELK 分析 - ✅ 健康检查接口
/healthz必须有 - ✅ Dockerfile 多阶段构建,减小镜像体积
- ✅ Prometheus metrics 接入(用
fastapi-prometheus)
算法?其实也在后端!
很多人以为算法只是 LeetCode 刷题,但在后端,算法思维直接影响性能。
比如我们有个“实时排行榜”需求,最初用 MySQL ORDER BY score LIMIT 100,用户一多就慢成狗。后来改成 Redis 的 ZSET,查询 O(log N),瞬间丝滑。
FastAPI 里集成 Redis 很简单:
from redis.asyncio import Redis
redis = Redis(host="localhost", port=6379, decode_responses=True)
@app.get("/leaderboard")
async def get_leaderboard():
top_users = await redis.zrevrange("scores", 0, 99, withscores=True)
return [{"user_id": u, "score": s} for u, s in top_users]
你看,选对数据结构,比优化框架重要十倍。这也是为什么我一直觉得:后端工程师不能只会 CRUD,得懂点算法和系统设计。
结语:Gap 期不是浪费,是技术复利
现在我重新找工作,面试官问我:“裸辞半年干嘛了?”
我说:“研究 FastAPI,还顺手把以前项目的性能问题复盘了一遍。”
他们眼睛一亮——因为很多公司正在从 Flask/Django 迁移到 FastAPI,但没人敢动,怕出事。而我,已经在线下跑了三个月压测,还写了完整的监控方案。
技术人的 Gap 期,不该是焦虑和内耗,而是把以前欠下的技术债,一笔一笔还清。
FastAPI 不是银弹,但它是一个信号:Python 后端正在进化。我们不必立刻切 Go,但必须拥抱异步、拥抱类型、拥抱性能意识。
最后吐槽一句:上周投了个岗位,JD 写“精通 FastAPI”,结果面完发现他们还在用 Python 2.7……算了,这种公司不去也罢。
如果你也在学 FastAPI,或者正被性能问题折磨,欢迎留言交流。我 VSCode 里装了一堆插件,连 .env 自动提示都有,说不定能帮上忙。
本文所有代码已整理到 GitHub,搜索 “fastapi-performance-playbook” 即可。别 star,star 了我也收不到钱 😅

评论 0