You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI中pymongo同步路由比motor异步路由慢太多?求排查

FastAPI异步路由+Motor性能远低于同步路由+pymongo问题排查

问题场景

使用FastAPI时,参考MongoDB官方推荐采用Motor作为异步驱动,搭建了两个功能完全一致的数据库查询路由:

  • 异步路由:使用AsyncIOMotorClient,接口路径/test
  • 同步路由:使用MongoClient,接口路径/test-sync

在300用户(约60请求/秒)的压测下,异步路由平均响应时间达27秒,而同步路由仅需50ms。已尝试调整Docker容器worker数量、增加CPU/内存资源、配置ECS额外任务,但问题未解决。/health接口压测响应正常,排除整体资源瓶颈。

相关代码

db.py

client = AsyncIOMotorClient(
    mongo_con_string,
)
sync_client = MongoClient(
    mongo_con_string,
)

mongo_db = client["test"]
sync_mongo_db = sync_client["test"]

views.py

@test_router.get("/test", status_code=200, response_description="")
async def get_articles():
        collection = mongo_db[TEST_TABLE]
        articles = await collection.find().to_list(1000)
        articles_str = json.dumps(articles, default=str)


@test_router.get("/test-sync", status_code=200, response_description="")
def get_articles_sync():
        collection = sync_mongo_db[TEST_TABLE]
        articles = collection.find().to_list(1000)
        articles_str = json.dumps(articles, default=str)

Dockerfile

FROM python:3.11

WORKDIR /code

COPY ./api/requirements.txt /code/requirements.txt

RUN pip install --upgrade -r /code/requirements.txt

COPY ./api/app /code/app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers", "--workers", "10"]

可能的问题原因及解决方案

1. Motor连接池配置不合理

AsyncIOMotorClient默认连接池大小可能远小于同步MongoClient,导致高并发下请求排队等待连接。

  • 解决方案:显式配置连接池参数,增加最大连接数:
client = AsyncIOMotorClient(
    mongo_con_string,
    maxPoolSize=100,  # 调整为适合并发量的数值
    minPoolSize=10,
    maxIdleTimeMS=30000  # 闲置连接超时时间
)

2. 同步JSON序列化阻塞事件循环

json.dumps是同步CPU密集型操作,当序列化1000条文档时,会长时间阻塞异步事件循环,导致后续请求无法处理。而同步路由依赖线程池,每个请求的序列化操作在独立线程中执行,不会互相影响。

  • 解决方案:将序列化操作转移到线程池执行,避免阻塞事件循环:
import asyncio
import json

@test_router.get("/test", status_code=200, response_description="")
async def get_articles():
    collection = mongo_db[TEST_TABLE]
    articles = await collection.find().to_list(1000)
    # 用线程池执行同步序列化
    articles_str = await asyncio.get_event_loop().run_in_executor(
        None,
        lambda: json.dumps(articles, default=str)
    )
    return articles_str

或者使用更快的序列化库(如orjson、ujson)减少序列化耗时。

3. 事件循环效率问题

默认的asyncio事件循环性能可能不如uvloop,高并发下差异明显。

  • 解决方案:安装uvloop并指定Uvicorn使用该事件循环:
pip install uvloop

修改Dockerfile启动命令:

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers", "--workers", "10", "--loop", "uvloop"]

4. 数据库查询耗时验证

先确认是数据库查询慢还是后续处理慢:在异步路由中添加日志记录查询耗时:

import time

@test_router.get("/test", status_code=200, response_description="")
async def get_articles():
    collection = mongo_db[TEST_TABLE]
    start = time.time()
    articles = await collection.find().to_list(1000)
    print(f"DB query time: {time.time() - start:.2f}s")
    # ... 后续操作

如果查询耗时本身很长,需要检查MongoDB实例的索引、性能,确认异步客户端和同步客户端的连接配置(如是否使用相同的副本集、读写偏好)一致。

内容的提问来源于stack exchange,提问作者serp002

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:23:18