当我的应用程序运行时,我经常遇到连接池问题(一个是“达到大小5溢出10的QueuePool限制”,另一个是“致命:剩余连接插槽是为非复制超级用户连接保留的” )。
我感觉这是因为某些代码没有正确关闭连接,或者其他代码贪婪地试图打开新的代码但不应该,但我使用默认的SQL Alchemy设置,所以我假设池连接默认不应该是不合理的。我们使用scoped_session(sessionmaker())方式创建会话,因此支持多个线程。
所以我的主要问题是,是否有工具或方法来找出连接的去向?一旦创建了一个新的(不应该被创建),就能够看到,是否有任何明显的反模式可能导致这种效果?
金字塔非常没有意见,并且在数据库连接方面,似乎有两种主要方法(金字塔同样支持它)。在我们的例子中,当我开始工作时的代码库使用了一种方法(我将其称为“全局”方法)并且我们已经同意切换到另一种方法,该方法更少依赖于全局变量而更多地依赖于Pythonic习语。
关于我们的架构:该应用程序包含一个存储Pyramid项目的repo,然后提供许多其他git模块,每个模块都有自己的连接设置。 “全局”方式以非ORM方式连接到数据库,例如:
(in each repo's __init__ file)
def load_database:
global tables
tables['table_name'] = Table(
'table_name', metadata,
Column('column_name', String),
)
在整个代码中经常会出现相关的全局变量:
def function_needing_data(field_value):
global db, tables
select = sqlalchemy.sql.select(
[tables['table_name'].c.data], tables['table_name'].c.name == field_value)
return db.execute(select)
这个表变量被锁存到每个git仓库中,这增加了一些表定义,并且不知何故全局表设法工作,提供对所有表的访问。
我们采用的方法(虽然此时,代码中仍然存在两种方法的部分)是通过集中连接,将所有元数据绑定到它,然后以ORM方法查询数据库:
(model)
class ModelName(MetaDataBase):
__tablename__ = "models_table_name"
... (field values)
(function requiring data)
from models.db import DBSession
from models.model_name import ModelName
def function_needing_data(field_value):
return DBSession.query(ModelName).filter(
ModelName.field_value == field_value).all()
我们在很大程度上将代码转移到后一种感觉正确的方法,但也许我的意图是错误的。我不知道这两种方法中是否存在任何本质上的好坏,但是这种方法(其中一种方法)是问题的一部分,所以我们一直没有连接?有迹象表明我应该留意吗?
答案 0 :(得分:1)
当您使用Pyramid transaction manager(pyramid_tm)时,金字塔看起来效果最好(在处理连接池方面)。这个excellent article by Jon Rosebaugh提供了一些有用的见解,包括Pyramid应用程序通常如何设置数据库连接以及应该如何设置它们。
在我的情况下,有必要包含pyramid_tm包,然后删除我们手动提交会话更改的一些事件,因为如果没有看到不这样做的原因,pyramid_tm将自动提交更改。
[更新]
我继续存在连接池问题,尽管它们更少。经过大量调试后,我发现金字塔事务管理器(如果你正确使用它)应该不是问题。问题与我通过cron作业运行的脚本有关的其他连接池问题。脚本将在完成时释放它的连接,但是错误的代码设计可能会导致相同的脚本可以打开并在前一个脚本运行时开始运行(导致它们运行速度变慢) ,足够慢以便在脚本的第三个实例启动时同时运行,等等。)
这是一个更加语言和数据库无关的错误,因为它源于糟糕的工作脚本设计,但值得记住。就我而言,脚本有一个"&"最后,每个实例作为后台进程启动,等待10秒,然后产生另一个,而不是确保第一个作业开始并完成,然后等待10秒,然后再启动另一个。
希望这有助于调试这个非常令人沮丧和棘手的问题。