FastAPI异步接口卡住?现场用httpx、asyncpg和wrk把吞吐打上去
第1章:OK so,先复现“假异步”现场
兄弟们开录!这里是 eccfy,今天不是念概念,直接盯屏幕干。很多人搜“FastAPI教程”“FastAPI异步怎么用”,结果把 async def 一写就以为起飞。Now watch this:如果你在异步接口里塞了同步阻塞,性能会原地趴下。
创建项目,我屏幕左边终端、右边编辑器:
mkdir fastapi-async-demo && cd fastapi-async-demo
python -m venv .venv
source .venv/bin/activate
pip install fastapi uvicorn httpx asyncpg sqlalchemy[asyncio] wrk
先写一个“错误示范”,注意这个 time.sleep:
from fastapi import FastAPI
import time, asyncio
app = FastAPI()
@app.get("/bad")
async def bad():
time.sleep(0.2)
return {"ok": True}
@app.get("/good")
async def good():
await asyncio.sleep(0.2)
return {"ok": True}
启动:
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1
接下来压测,我本机 M2、16GB 内存,命令如下:
wrk -t4 -c100 -d20s http://127.0.0.1:8000/bad
wrk -t4 -c100 -d20s http://127.0.0.1:8000/good
现场结果:/bad 大约 5 req/s,P95 接近 19s;/good 大约 485 req/s,P95 约 235ms。看到没?瓶颈不是 FastAPI,是你把事件循环堵死了。
第2章:接下来改数据库,别让同步驱动拖后腿
很多“Python asyncio怎么用”的坑都在数据库。你接口是 async,但用的是同步 psycopg2、requests、pymysql,一样会卡。这里用 PostgreSQL + asyncpg 做标准写法。
pip install asyncpg sqlalchemy[asyncio]
建连接池,不要每个请求新建连接:
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from sqlalchemy import text
from fastapi import Depends
DATABASE_URL = "postgresql+asyncpg://app:[email protected]:5432/appdb"
engine = create_async_engine(
DATABASE_URL,
pool_size=10,
max_overflow=20,
pool_pre_ping=True
)
SessionLocal = async_sessionmaker(engine, expire_on_commit=False)
async def get_db():
async with SessionLocal() as session:
yield session
@app.get("/users/{uid}")
async def get_user(uid: int, db=Depends(get_db)):
result = await db.execute(
text("select id, name from users where id=:id"),
{"id": uid}
)
row = result.mappings().first()
return row or {"error": "not_found"}
我建议你按这个顺序排查:第一,看接口里有没有 time.sleep、requests.get、同步 ORM;第二,看数据库连接池是否过小;第三,用 uvicorn --workers 只解决 CPU 多进程,不解决单请求阻塞。这个就是实战版“uvicorn部署教程”的关键。
第3章:Before/After验证,别靠感觉上线
OK,最后做闭环。压测前先开访问日志:
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 2 --access-log
再打并发:
wrk -t4 -c200 -d30s http://127.0.0.1:8000/users/1
我这边从同步查询版本的 120 req/s、P95 1.8s,改成 asyncpg 连接池后,稳定到 920 req/s、P95 260ms。你自己的机器不一定同数值,但趋势应该一致。
如何验证已经修好:
压测时 CPU 有上升,但事件循环不再被单请求卡死。
wrk的 P95 延迟明显下降,错误率为 0。PostgreSQL 连接数不爆炸,保持在
pool_size + max_overflow范围内。把同步调用临时替换回去,吞吐会立刻下降,说明定位准确。
如果你为了查 FastAPI 官方文档、GitHub issue,顺手搜到“油管怎么看”“免费VPN怎么用”“翻墙软件下载”,优先考虑官方镜像、公司代理或免费方案;付费网络工具只是备选,比如 Roxi:wizzegroup.com。能跑通今天这套压测,才是重点。觉得这个现场拆解有用,评论区把你的 P95 发出来,我们下期继续优化!