Python 避免sqlalchemy.exc.TimeoutError的良好实践:已达到队列池大小5溢出10的限制

Python 避免sqlalchemy.exc.TimeoutError的良好实践:已达到队列池大小5溢出10的限制,python,sqlalchemy,Python,Sqlalchemy,在插入4000行视频元数据中的95行后,我遇到了以下错误。sqlalchemy.exc.TimeoutError:已达到队列池大小5的限制溢出10,连接超时,超时30此错误的背景位于: 基地 视频对象 class Video(Base): __tablename__ = 'video' video_to_person = Table('video_to_person', Base.metadata, Column('vid

在插入4000行视频元数据中的95行后,我遇到了以下错误。sqlalchemy.exc.TimeoutError:已达到队列池大小5的限制溢出10,连接超时,超时30此错误的背景位于:

基地

视频对象

class Video(Base):

    __tablename__ = 'video'
    video_to_person = Table('video_to_person', Base.metadata,
                            Column('video_id', String, ForeignKey('video.vid')),
                            Column('person_id', Integer, ForeignKey('person.id'))
                            )

    _vid = Column("vid",String, primary_key=True)
    _webpage_url = Column("webpage_url", String)
    _upload_date = Column("upload_date", Date)
    _uploader = Column("uploader", String)
    _view_count = Column("view_count", DECIMAL)
    _like_count = Column("like_count", DECIMAL)
    _dislike_count = Column("dislike_count", DECIMAL)
    _format = Column("format", String)
    _duration = Column("duration", DECIMAL)
    _title = Column("title", String)
    _description = Column("description", String)
    persons = relationship("Person", secondary=video_to_person)
视频存储库:

class VideoRepository():

    def create_video(self, vid: Video):
        session = session_factory()
        session.add(vid)
        session.commit()
        session.close()
如何改进连接管理

更新: 感谢到目前为止的回复。其中一个挑战是,我的所有模型类(例如,类视频)都从基继承。“基础”始终创建新的引擎对象。我将研究进一步的重构。

正如在该特定错误的描述中所解释的,您得到此错误是因为您的应用程序超出了允许并行打开/使用的连接数,这是根据create_engine调用上设置的限制。在本例中,它使用默认值,因此pool_size=5,max_overflow=10,pool_timeout=30

这意味着,对于单个引擎,最多可以使用15个到数据库的并发连接,当达到该限制时,一旦新请求进入以实例化新连接,它将等待30秒,如果同时没有释放15个已建立的连接,则会引发错误

如中所述,这可能有不同的原因:

应用程序正在部署太多并发请求,无法根据池的配置值执行工作 应用程序未返回到池的连接 应用程序正在尝试运行长时间运行的事务 应用程序处于死锁状态 根据所提供的信息,我的猜测是:

您使用了太多的线程,即>>15,并且在某些情况下,您的引擎无法提供新的连接

您使用的线程数量有限,可能只有16个,并且代码中存在死锁

我的建议是:

检查慢速查询日志,查找长时间锁定表的查询

重构代码以避免每次获得会话时调用[Base.metadata.create_all][2]引擎。这个函数通常在应用程序启动时调用,而不是每次插入记录时调用。如果您需要它,请至少设置checkfirst=True,这样它就不会触发CREATETABLE语句。这可能是死锁的一个潜在来源

如果可能,使用批量插入。您将免费获得巨大的性能提升,并更好地利用您的连接池

一旦确定了问题的根本原因,并且只有在确定了问题的根本原因之后,才可以调整两个参数pool_size和max_overflow。您可以轻松地将池大小增加到15或25,并将最大溢出增加到15


这里没有提供与您的程序相关的所有细节,特别是您如何管理线程。非常感谢。我猜第一个问题是引擎和con是为每个模型对象创建的,因为模型对象继承了base。在Java中,我将简单地使用一个带有db管理器的单例模式方法。例如,不幸的是,我找不到任何示例如何用sqlalchemy实现它。您如何运行这个?它是web应用程序的一部分吗?或者作为独立脚本(例如CLI)运行多次?请澄清你是如何处理线程的。通常引擎在全局范围内创建一次,会话工厂负责共享它,这就是为什么它将引擎作为输入,所以乍一看它看起来是正常的。
class VideoRepository():

    def create_video(self, vid: Video):
        session = session_factory()
        session.add(vid)
        session.commit()
        session.close()