泄漏数据库连接:PostgreSQL,SQLAlchemy,Flask

3
我正在使用PostgreSQL 9.3和SQLAlchemy 0.8.2,并且遇到了数据库连接泄漏的问题。应用程序部署后会消耗约240个连接。在接下来的30小时内,这个数字逐渐增长到500,在这时PostgreSQL将开始丢失连接。
我使用SQLAlchemy的上下文线程本地会话
from sqlalchemy import orm, create_engine

engine = create_engine(os.environ['DATABASE_URL'], echo=False)
Session = orm.scoped_session(orm.sessionmaker(engine))

针对Flask Web应用程序,.remove()调用发送到Session代理对象,这会发生在请求拆除期间:

@app.teardown_request
def teardown_request(exception=None):
    if not app.testing:
        Session.remove()

这应该与 Flask-SQLAlchemy 所做的相同。

我还有一些定期任务在循环中运行,每次迭代循环时我都调用 .remove()

def run_forever():
    while True:
        do_stuff(Session)
        Session.remove()

我做错了什么可能导致连接泄漏?

曾经遇到过类似的问题,通过在@app.teardown_request中调用sqlalchemy.engine.Engine.dispose()解决了。请参考我的这个问题:https://stackoverflow.com/questions/69886037/sqlalchemy-database-session-not-being-removed-after-web-request - William May
2个回答

4
如果我没有记错,使用SQLAlchemy时,scoped_session()用于创建您可以从多个位置访问的会话。也就是说,在一个方法中创建一个会话,并在另一个方法中使用它,而无需明确地传递会话对象。 它通过保持会话列表并将其与“作用域ID”关联来实现这一点。默认情况下,为了获得作用域ID,它使用当前线程ID;因此您有每个线程的会话。您可以提供一个scopefunc来提供每个请求一个ID,例如:
# This is (approx.) what flask-sqlalchemy does:
from flask import _request_ctx_stack as context_stack

Session = orm.scoped_session(orm.sessionmaker(engine),
                             scopefunc=context_stack.__ident_func__)

此外,请注意其他有关执行后台任务的答案和评论。

1
还要注意从0.9开始,大多数情况下更适用的是 _app_ctx_stack。https://github.com/mitsuhiko/flask/blob/7f3867491570746a4c14bdaa5bd59ec1b64cbfea/docs/upgrading.rst#version-09 - awsum

0

首先,这是一种非常糟糕的运行后台任务的方式。尝试使用任何ASync调度程序,如celery。

根据提供的信息,我不是100%确定,但我想知道每个页面加载是否都会启动一个新的数据库连接,然后监听通知。如果是这种情况,我想知道数据库连接是否被有效地从池中删除,因此会在下一个页面加载时创建。

如果是这种情况,我的建议是拥有一个专门用于监听通知的单独的DBI数据库句柄,以便这些通知不会在队列中处于活动状态。这可能在您的工作流之外完成。

另外

特别是在进行多个同时请求时发生泄漏。同时,我可以看到一些请求未完成查询执行并超时。您可以编写一些内容来自行管理此问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接