2014-09-02 121 views
2

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

我使用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)) 

对于瓶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() 

我在做什么错误可能导致泄漏的连接?

+1

是否有你用flask-sqlalchemy标记过的原因,但没有使用flask-sqlalchemy来管理你的会话? – davidism 2014-09-04 15:07:36

+2

这也是一种非常糟糕的方式来运行后台任务。考虑使用芹菜,在Flask文档中有一种将应用上下文和数据库会话导入任务的模式。 – davidism 2014-09-04 15:08:58

+1

应用程序是如何部署的? – 2014-09-07 15:15:21

回答

0

首先,这是一个非常糟糕的方式来运行后台任务。尝试像芹菜这样的任何ASync调度程序。

不是100%确定,所以这是基于提供的信息的一点猜测,但我想知道每个页面加载是否正在启动一个新的数据库连接,然后侦听通知。如果是这样的话,我不知道数据库连接是否被有效地从池中删除,因此在下一页加载时被创建。

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

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

3

如果我从我的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 2015-12-05 15:44:32

相关问题