Python 为Gunicorn上运行的Flask SQLAlchemy应用程序选择数据库池大小

Python 为Gunicorn上运行的Flask SQLAlchemy应用程序选择数据库池大小,python,database,sqlalchemy,flask-sqlalchemy,gunicorn,Python,Database,Sqlalchemy,Flask Sqlalchemy,Gunicorn,我有一个运行在Gunicorn中的Flask SQLAlchmey应用程序连接到PostgreSQL数据库,我很难确定pool\u size值应该是多少,以及我应该期望多少个数据库连接 这是我对事物如何运作的理解: Python 3.7中的进程不共享内存 每个Gunicorn员工都有自己的流程 因此,每个Gunicorn工作者都将获得自己的数据库连接池副本,而不会与任何其他工作者共享 Python中的线程确实共享内存 因此,Gunicorn工作线程中的任何线程都将共享一个数据库连接池 到目前

我有一个运行在Gunicorn中的Flask SQLAlchmey应用程序连接到PostgreSQL数据库,我很难确定
pool\u size
值应该是多少,以及我应该期望多少个数据库连接

这是我对事物如何运作的理解:

  • Python 3.7中的进程不共享内存
  • 每个Gunicorn员工都有自己的流程
  • 因此,每个Gunicorn工作者都将获得自己的数据库连接池副本,而不会与任何其他工作者共享
  • Python中的线程确实共享内存
  • 因此,Gunicorn工作线程中的任何线程都将共享一个数据库连接池
到目前为止这是正确的吗?如果这是正确的,那么对于在Gunicorn中运行的同步烧瓶应用程序:

  • 最大数据库连接数=(工作线程数)*(每个工作线程数)
  • 在一个worker中,它是否会比其他worker使用更多的池连接

是否有理由认为
pool\u size
应该大于线程数?因此,对于使用
gunicorn--workers=5--threads=2 main:app启动的gunicorn应用程序,
pool_size
应该是2吗?如果我只使用worker,而不使用线程,那么有没有理由让
池大小大于1?

我认为您的理解非常好。单个WSGI工作线程中的线程确实将共享一个连接池;因此,理论上,数据库连接的最大数量是
(工作者数量)*N
,其中
N=pool\u size+max\u overflow
。(我不确定Alchemy将max_overflow设置为什么,但这是等式的一个重要部分-请参阅它的含义。)


实际上,如果您只使用Flask SQLAlchemy提供给您的线程范围会话,那么每个线程最多有一个连接;因此,如果您的线程数小于
N
,那么您的上限实际上是
(工作线程数)*(每个工作线程数)

加上我的2美分。您的理解是正确的,但有一些想法需要考虑:

  • 如果您的应用程序是IO绑定的(例如与数据库对话),那么您确实希望有多个线程。否则,您的CPU将永远无法达到100%的利用率。您需要测试线程的数量以获得正确的数量,通常使用负载测试工具并比较每秒请求数和CPU利用率

  • 考虑到工作者数量和连接之间的关系,您可以看到在更改工作者数量时,需要调整最大池大小。这可能很容易忘记,因此可能一个好主意是将池大小设置为略高于工人数量,例如,该数量的两倍

  • postgresql为每个连接创建一个进程,当您有很多gunicorn进程时,可能无法很好地扩展。我会选择一些连接池,它位于你的应用程序和数据库之间(我想pgbouncer是最流行的)


只是在@matino的网站上添加了我自己最近的一些经验。WSGI应用程序也可以从异步工作者中受益。我将在这里添加一些关于
异步工作者
连接池
的内容

我们最近在生产中遇到了一些类似的问题。我们的交通量在1-2天内猛增,由于某种原因,所有的请求都被阻塞了。我们将gunicorn与
gevent
异步工作者一起用于我们的
django
应用程序。事实证明,psql连接是许多请求停止(并最终超时)的原因

建议的并发请求数为
(2*CPU)+1
。因此,在同步场景中,您的计算如下:
(workers\u num*threads\u num)
gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 django:app