如何使用 Flask-SQLAlchemy 避免 QueuePool limit 错误?
How to avoid the QueuePool limit error using Flask-SQLAlchemy?
我正在使用 Flask-SQLAlchemy 和 Postgre DB 开发一个网络应用程序,然后我的网页中有这个下拉列表,在 selecting 之后从 select 填充到数据库几次不同的值我得到“sqlalchemy.exc.TimeoutError:”。
我的包的版本是:
Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.8.6
SQLAlchemy==1.4.15
我的数据库连接参数设置为:
app.config['SQLALCHEMY_POOL_SIZE'] = 20
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 20
app.config['SQLALCHEMY_POOL_TIMEOUT'] = 5
app.config['SQLALCHEMY_POOL_RECYCLE'] = 10
我得到的错误是:
sqlalchemy.exc.TimeoutError: QueuePool limit of size 20 overflow 20 reached, connection timed out, timeout 5.00 (Background on this error at: https://sqlalche.me/e/14/3o7r)
将 'SQLALCHEMY_MAX_OVERFLOW' 的值从 20 更改为 100 后,下拉列表中的一些值发生更改后出现以下错误。
psycopg2.OperationalError: connection to server at "localhost" (::1), port 5432 failed: FATAL: sorry, too many clients already
每次从下拉列表中 select 编辑一个新值时,都会触发对数据库的四个查询,它们用于将结果填充到我的 HTML 中的四个相应表中查询。
我在每次查询数据库后都有一个 'db.session.commit()' 语句,但即使我有它,在我的下拉列表的一些值更改后我也会收到此错误。
我知道我应该寻求正确管理我的连接会话,但我正在努力解决这个问题。我考虑过将池超时设置为 5 秒,而不是默认的 30 秒,希望以更快的方式关闭会话并返回池,但似乎没有帮助。
根据@snakecharmerb 的建议,我检查了以下输出:
select * from pg_stat_activity;
我 运行 webapp 有 10 个不同的值,然后它向我显示错误,这意味着所有 20+20 个会话都被使用并处于 'idle in transaction' 状态。
有人对我应该改变或寻找什么有什么想法建议吗?
您正在泄漏连接。
有点违反直觉,
您可能会发现使用 较低 池限制可以获得更好的结果。
一个给定的 python 线程只需要一个池连接,
对于您正在执行的简单的单数据库查询。
将限制设置为 1
,0
溢出,
将使您更早地注意到泄漏的连接。
这使得更容易将责任归咎于泄露它的源代码。
就目前而言,您有很多代码,并且错误被推迟了
直到发出许多查询之后,
更难推理系统行为。
我假设您使用的是 sqlalchemy 1.4.29。
为避免泄漏,请尝试使用此方法:
from contextlib import closing
from sqlalchemy import create_engine, text
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine(some_url, future=True, pool_size=1, max_overflow=0)
get_session = scoped_session(sessionmaker(bind=engine))
...
with closing(get_session()) as session:
try:
sql = """yada yada"""
rows = session.execute(text(sql)).fetchall()
session.commit()
...
# Do stuff with result rows.
...
except Exception:
session.rollback()
我在 Whosebug 的另一个 post 中找到了解决我所面临问题的方法。
当您将 Flask 应用程序分配给 db 变量时,除了指示它应该使用哪个 Flask 应用程序之外,您还可以传递会话选项,如下所示:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app, session_options={'autocommit': True})
使用 'autocommit' 解决了我的问题。
现在,按照建议,我正在使用:
app.config['SQLALCHEMY_POOL_SIZE'] = 1
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 0
现在一切正常。
原来对我有帮助的post是:Autocommit in Flask-SQLAlchemy
@snakecharmerb,@jorzel,@J_H -> 感谢您的帮助!
我正在使用 Flask-SQLAlchemy 和 Postgre DB 开发一个网络应用程序,然后我的网页中有这个下拉列表,在 selecting 之后从 select 填充到数据库几次不同的值我得到“sqlalchemy.exc.TimeoutError:”。
我的包的版本是:
Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.8.6
SQLAlchemy==1.4.15
我的数据库连接参数设置为:
app.config['SQLALCHEMY_POOL_SIZE'] = 20
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 20
app.config['SQLALCHEMY_POOL_TIMEOUT'] = 5
app.config['SQLALCHEMY_POOL_RECYCLE'] = 10
我得到的错误是:
sqlalchemy.exc.TimeoutError: QueuePool limit of size 20 overflow 20 reached, connection timed out, timeout 5.00 (Background on this error at: https://sqlalche.me/e/14/3o7r)
将 'SQLALCHEMY_MAX_OVERFLOW' 的值从 20 更改为 100 后,下拉列表中的一些值发生更改后出现以下错误。
psycopg2.OperationalError: connection to server at "localhost" (::1), port 5432 failed: FATAL: sorry, too many clients already
每次从下拉列表中 select 编辑一个新值时,都会触发对数据库的四个查询,它们用于将结果填充到我的 HTML 中的四个相应表中查询。
我在每次查询数据库后都有一个 'db.session.commit()' 语句,但即使我有它,在我的下拉列表的一些值更改后我也会收到此错误。
我知道我应该寻求正确管理我的连接会话,但我正在努力解决这个问题。我考虑过将池超时设置为 5 秒,而不是默认的 30 秒,希望以更快的方式关闭会话并返回池,但似乎没有帮助。
根据@snakecharmerb 的建议,我检查了以下输出:
select * from pg_stat_activity;
我 运行 webapp 有 10 个不同的值,然后它向我显示错误,这意味着所有 20+20 个会话都被使用并处于 'idle in transaction' 状态。
有人对我应该改变或寻找什么有什么想法建议吗?
您正在泄漏连接。
有点违反直觉,
您可能会发现使用 较低 池限制可以获得更好的结果。
一个给定的 python 线程只需要一个池连接,
对于您正在执行的简单的单数据库查询。
将限制设置为 1
,0
溢出,
将使您更早地注意到泄漏的连接。
这使得更容易将责任归咎于泄露它的源代码。
就目前而言,您有很多代码,并且错误被推迟了
直到发出许多查询之后,
更难推理系统行为。
我假设您使用的是 sqlalchemy 1.4.29。
为避免泄漏,请尝试使用此方法:
from contextlib import closing
from sqlalchemy import create_engine, text
from sqlalchemy.orm import scoped_session, sessionmaker
engine = create_engine(some_url, future=True, pool_size=1, max_overflow=0)
get_session = scoped_session(sessionmaker(bind=engine))
...
with closing(get_session()) as session:
try:
sql = """yada yada"""
rows = session.execute(text(sql)).fetchall()
session.commit()
...
# Do stuff with result rows.
...
except Exception:
session.rollback()
我在 Whosebug 的另一个 post 中找到了解决我所面临问题的方法。
当您将 Flask 应用程序分配给 db 变量时,除了指示它应该使用哪个 Flask 应用程序之外,您还可以传递会话选项,如下所示:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app, session_options={'autocommit': True})
使用 'autocommit' 解决了我的问题。
现在,按照建议,我正在使用:
app.config['SQLALCHEMY_POOL_SIZE'] = 1
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 0
现在一切正常。
原来对我有帮助的post是:Autocommit in Flask-SQLAlchemy
@snakecharmerb,@jorzel,@J_H -> 感谢您的帮助!