避免 sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 10 的良好做法

wuz*_*wuz 2 python sqlalchemy

在插入 4000 行中的 95 行视频元数据后,我遇到了以下错误。sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 10 达到,连接超时,超时 30(此错误的背景:http://sqlalche。我/e/3o7r)。

根据

engine = db.create_engine(connect_string)
con = engine.connect()
_SessionFactory = sessionmaker(bind=engine)
Base = declarative_base()

def session_factory():
    Base.metadata.create_all(engine)
    return _SessionFactory()
Run Code Online (Sandbox Code Playgroud)

视频对象

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)
Run Code Online (Sandbox Code Playgroud)

视频库:

class VideoRepository():

    def create_video(self, vid: Video):
        session = session_factory()
        session.add(vid)
        session.commit()
        session.close()
Run Code Online (Sandbox Code Playgroud)

如何改进连接管理?

更新:感谢您到目前为止的答复。挑战之一是我所有的模型类,例如(类 Video)都继承自 Base。Base 总是会创建一个新的引擎对象。我将研究进一步的重构。

bag*_*ard 5

如该特定错误的文档中所述,您收到此错误是因为根据 create_engine 调用设置的限制,您的应用程序超出了允许并行打开/使用的连接数。在这种情况下,它使用默认值,因此pool_size=5, max_overflow=10pool_timeout=30

这意味着使用单个引擎,您最多可以使用 15 个与数据库的并发连接,当达到该限制时,一旦有新请求进入实例化新连接,它将等待 30 秒,如果 15 个已经没有-已建立的连接在此期间被释放,它引发了错误。

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

  • 应用程序正在处理太多并发请求以根据池的配置值执行工作
  • 应用程序未将连接返回到池
  • 应用程序正在尝试运行长时间运行的事务
  • 应用程序陷入僵局

鉴于提供的信息,我的猜测是:

  • 您使用了太多线程(即 >>15),并且在某些时候您的引擎无法提供新的连接

  • 您使用的线程数量有限(可能是 16 个),并且您的代码出现死锁。

我的建议:

  • 检查您的慢查询日志并查找长时间锁定表的查询

  • 重构代码以避免[Base.metadata.create_all][2](engine)每次获得会话时都调用。这个东西通常在应用程序启动时调用,而不是每次插入记录时调用。如果你需要它,至少设置checkfirst=True它不会触发 CREATE TABLE 语句。这可能是导致死锁的潜在原因

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

  • 一旦确定了问题的根本原因(并且仅在此之后),您就可以调整 2 个参数pool_sizemax_overflow。您可以轻松地将 pool_size 增加到 15 或 25,将 max_overflow 增加到 15