【问题标题】:Leaking database connections: PostgreSQL, SQLAlchemy, Flask泄露数据库连接:PostgreSQL、SQLAlchemy、Flask
【发布时间】:2014-10-26 17:30:05
【问题描述】:

我正在运行 PostgreSQL 9.3 和 SQLAlchemy 0.8.2 并且遇到数据库连接泄漏。部署应用程序后消耗大约 240 个连接。在接下来的 30 小时内,这个数字逐渐增加到 500,届时 PostgreSQL 将开始丢弃连接。

我使用 SQLAlchemy thread-local sessions:

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()

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

【问题讨论】:

标签: python postgresql flask sqlalchemy


【解决方案1】:

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

不是 100% 肯定,所以根据提供的信息,这有点猜测,但我想知道每个页面加载是否正在启动一个新的数据库连接,然后该连接正在侦听通知。如果是这种情况,我想知道 db 连接是否已从池中有效删除,并在下一页加载时创建。

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

还有

特别是,当同时发出多个请求时会发生泄漏。同时,我可以看到一些请求未完成查询执行和超时。你可以自己写一些东西来管理它。

【讨论】:

    【解决方案2】:

    如果我在使用 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__)
    

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-03
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 2018-02-09
    • 2017-07-07
    • 2018-06-13
    • 1970-01-01
    相关资源
    最近更新 更多