避免sqlalchemy.exc.TimeoutError的良好实践:达到大小5溢出10的QueuePool限制

时间:2019-09-08 18:59:45

标签: python sqlalchemy

我插入了4000行中的95行视频元数据后,遇到以下错误。sqlalchemy.exc.TimeoutError:大小为5的QueuePool溢出10达到极限,连接超时,超时30(此错误的背景位于:{{3 }}。

基础

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

视频对象

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

如何改善连接管理?

更新: 感谢到目前为止的答复。挑战之一是我所有的模型类(视频类)从Base继承。 Base始终创建一个新的引擎对象。我将研究进一步的重构。

1 个答案:

答案 0 :(得分:1)

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

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

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

  
      
  • 应用程序正在根据池中配置的值处理太多并发请求以完成工作
  •   
  • 应用程序未将连接返回到池
  •   
  • 该应用程序正在尝试运行长时间运行的事务
  •   
  • 应用程序处于死锁状态
  •   

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

  • 您使用了过多的线程(即>> 15),有时引擎无法提供新的连接

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

我的建议:

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

  • 重构代码,以免每次会话时都调用[Base.metadata.create_all][2](engine)。通常在应用程序启动时(而不是每次插入记录时)调用此东西。如果需要,请至少设置checkfirst=True,以免触发CREATE TABLE语句。这可能是造成僵局的原因

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

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