如何在 SQLAlchemy 中为 ASGI 应用程序正确设置 pool_size (和 max_overflow)

问题描述 投票:0回答:2

我们正在使用 fastapi、uvicorn、sqlalchemy 和 PostgreSQL 构建 ASGI 应用程序。问题是:与具有多个工作线程的 WSGI 应用程序相比,我们应该如何在

pool_size
中设置
create_async_engine
才不会成为瓶颈?

据我了解,在 WSGI 应用程序中,如果我们运行

N
进程,每个进程有
M
个线程(和
pool_size=M
),我们最多将获得
N * M
个连接。但是 ASGI 怎么样(如果我们有一个进程)——可以打开多少个连接?还有
pool_size
(因为我们每个进程只创建一个
AsyncEngine
)?那么我们应该将其设置为
pool_size=N * M

而且,如果我们简单地增加这个数字,那么我们就能够同时向数据库发出更多

await
可用请求,对吗?

其背后的直觉是什么?

提前致谢!

sqlalchemy python-asyncio asgi
2个回答
0
投票

async
默认情况下,工作将在单个线程上“尽可能快地”进行。 这意味着在最佳情况下,放置 N =(2 X CPU 计数)个进程只会使 CPU 核心饱和。最有可能发生的是数据库 I/O 方面的瓶颈。这个问题已经过去两年了,与此同时,带有原生 AsyncIO 的 PsycoPG3 连接器(安装“psycopg”Python 项目作为依赖项时的默认连接器)已经发布 - 它肯定是比 PsycoPG2 或旧的“aiopg”是一个较小的项目,在底层使用同步 PsycoPG2(可能带有线程池)。

也就是说,传入的 HTTP 请求将产生新的任务,无论工作线程是否已被未完成的数据库相关异步任务所饱和。它们只会“堆积”,很自然,数据库请求将首先解决,并释放资源:异步任务确实是轻等待,数以万计的任务只占用表示其状态所需的内存当他们等待解决方案时 - 但“一切都应该顺利”部分可能并非如此。

另一方面,就像 N 进程 X M 线程方法一样,根本不可能知道“要处理的最大请求”。新连接被简单地接受,它们将运行并创建它们需要解决的 I/O 任务。因此,线程数量“M”所需的任何手动调整都消失了:系统将自然饱和。

因此,为了安全起见,如果有很多正在进行的任务,最好使用一种机制来避免接受新的 HTTP 连接。问题是这不能在视图代码中完成,因为此时已经接受了一个任务 - 一个 ASGI 中间件可以使用信号量来计算活动视图的数量(或任务总数),并发出信号上游层(例如,通过返回 HTTP 131 错误)认为资源已饱和可能是一件好事。 (对于在容器编排场景(Kubernetes)中运行的系统,这可能会触发额外 Pod 的配置)。但除此之外,“放手”就可以了,让其他层决定何时进行水平缩放即可。 当然,您的另一个瓶颈在某些时候将是数据库。


-2
投票

在 sqlalchemy 中添加池大小和最大溢出,你可以使用

engine = create_async_engine(
    settings.ASYNC_SQLALCHEMY_URL,
    echo=settings.SQLALCHEMY_ECHO,
    pool_size=20,
    max_overflow=10,
)

在 sqlalchemy 中,您没有最大池大小,但建议池大小为 20

© www.soinside.com 2019 - 2024. All rights reserved.