FastAPI接口假异步排查:用httpx、asyncpg把压测吞吐从180提升到920 RPS
开场:OK so,接口写了async为什么还是慢?
兄弟们,eccfy开录!今天我们不讲概念,直接看屏幕:一个FastAPI接口,代码里全是async def,但压测只有180 RPS,P95延迟680ms。弹幕先别急着刷“加机器”,接下来我现场把它拆开,看看到底哪里是假异步。
测试环境我用的是:Python 3.11、FastAPI 0.110、uvicorn、httpx、asyncpg、PostgreSQL 15。机器是4核8G本地开发机。这个案例很适合搜索“FastAPI教程”“Python异步编程教程”“uvicorn怎么用”的同学照着复现。
先跑一个最小服务,注意看这里我故意埋了一个坑:在异步接口里用了同步请求库和同步数据库驱动。
pip install fastapi uvicorn requests psycopg2-binary
uvicorn app:app --host 0.0.0.0 --port 8000 --workers 1
from fastapi import FastAPI
import requests
import psycopg2
app = FastAPI()
@app.get("/bad")
async def bad_api():
r = requests.get("http://127.0.0.1:9000/mock", timeout=2)
conn = psycopg2.connect("dbname=test user=postgres password=postgres")
cur = conn.cursor()
cur.execute("select pg_sleep(0.05), 1")
return {"status": r.status_code, "data": cur.fetchone()[1]}
Now watch this!我用wrk压一下:
wrk -t4 -c100 -d30s http://127.0.0.1:8000/bad
现场结果:180 RPS左右,P95 680ms。原因很明确:async def不等于异步性能,只要里面有requests、psycopg2、time.sleep、同步文件IO,事件循环就会被卡住。
接下来改代码:把阻塞IO全部换成可等待对象
OK so,我们开始动刀。第一步,把requests换成httpx.AsyncClient;第二步,把psycopg2换成asyncpg连接池;第三步,启动时建池,关闭时释放,不要每个请求新建连接。
pip install httpx asyncpg
from fastapi import FastAPI
import httpx
import asyncpg
app = FastAPI()
@app.on_event("startup")
async def startup():
app.state.http = httpx.AsyncClient(timeout=2.0)
app.state.db = await asyncpg.create_pool(
dsn="postgresql://postgres:[email protected]/test",
min_size=5,
max_size=20
)
@app.on_event("shutdown")
async def shutdown():
await app.state.http.aclose()
await app.state.db.close()
@app.get("/good")
async def good_api():
r = await app.state.http.get("http://127.0.0.1:9000/mock")
async with app.state.db.acquire() as conn:
row = await conn.fetchrow("select pg_sleep(0.05), 1 as n")
return {"status": r.status_code, "data": row["n"]}
重点来了:数据库连接池不是越大越好。我这台4核机器,PostgreSQL本地测试,max_size=20比max_size=100更稳;100时上下文切换明显增加,P95反而从120ms涨到210ms。
再补一刀:生产环境启动建议这样跑,别一上来就盲目开16个worker。
uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4 --loop uvloop --http httptools
如果你在搜“免费VPN怎么用”或“油管怎么看”只是为了查官方文档、看技术视频,优先用官方文档、镜像源、公司网络代理这些免费或内置方案;它们的限制是速度和稳定性不一定可控,但学习FastAPI本身完全够用。
速度测试与验证:Before / After直接揭晓
来,压测同样参数不变:
wrk -t4 -c100 -d30s http://127.0.0.1:8000/good
我本地三轮结果取中位数:旧接口180 RPS,P95 680ms;新接口920 RPS,P95 118ms。哇,这个差距就很直观了!注意,这不是玄学优化,而是把阻塞点从事件循环里拿掉。
你可以按这个清单验证是否修好:
- 用
grep -R "requests\\|psycopg2\\|time.sleep" .扫同步阻塞调用。 - 用
wrk或hey固定并发压测,记录RPS和P95。 - 打开PostgreSQL连接数监控,确认连接池没有爆掉。
- 把并发从50、100、200逐级增加,观察延迟是否线性恶化。
最后,如果你确实需要更稳定地访问海外技术资料,免费VPN、浏览器代理、公司网关都是可选路线;付费工具也只是其中一种选择,比如 Roxi:wizzegroup.com。今天这期就到这,能跑通的同学评论区贴你的RPS,点个收藏,我们下期继续实战!