检查日志的时候发现系统有一个报错。
QueuePool limit of size 500 overflow 10 reached, connection timed out, timeout 30
查阅官方文档
这可能是最常见的运行时错误,因为它直接涉及到应用程序的工作量超过配置的限制,该限制通常适用于几乎所有SQLAlchemy应用程序。
以下几点总结了此错误的含义,首先从大多数SQLAlchemy用户应该已经熟悉的最基本点开始。
-
默认情况下,SQLAlchemy Engine对象使用连接池 -这意味着当使用Engine对象的SQL数据库连接资源,然后释放该资源时,数据库连接本身仍保持与数据库的连接并返回给内部队列,可以再次使用它。即使代码看起来似乎正在结束与数据库的对话,在许多情况下,应用程序仍将保持固定数量的数据库连接,该连接将持续到应用程序结束或显式处置池为止。
-
由于存在池,因此当应用程序使用SQL数据库连接时(通常是使用Engine.connect() ORM或使用ORM进行查询时)Session,此活动不一定会在连接对象创建时建立与数据库的新连接。获得 相反,它会向连接池咨询连接,该连接通常会从池中检索要重新使用的现有连接。如果没有可用的连接,则该池将创建一个新的数据库连接,但前提是该池尚未超过配置的容量。
-
大多数情况下使用的默认池称为QueuePool。当您要求该池为您提供连接但没有可用连接时,如果正在使用的连接总数小于配置的值,它将创建一个新的连接。该值等于 池大小加上最大溢出量。这意味着如果您已将引擎配置为:
engine = create_engine("mysql://u:p@host/db", pool_size=10, max_overflow=20)
-
以上内容Engine将允许最多30个连接在任何时候进行,不包括从引擎上断开或无效的连接。如果对新连接的请求到达,并且应用程序的其他部分已经使用了30个连接,则连接池将阻塞一段固定的时间,然后超时并发出此错误消息。
-
为了允许一次使用更多数量的连接,可以使用create_engine.pool_size和create_engine.max_overflow 传递给create_engine()函数的参数来调整池 。使用create_engine.pool_timeout参数配置等待连接可用的超时 。
-
通过将create_engine.max_overflow值设置为“ -1”,可以将池配置为无限溢出 。使用此设置,该池仍将保持固定的连接池,但是它永远不会在请求新的连接时阻塞。如果没有可用的连接,它将无条件建立新连接。
-
但是,以这种方式运行时,如果应用程序存在用尽所有可用连接资源的问题,它将最终达到数据库本身上已配置的可用连接限制,这将再次返回错误。更严重的是,当应用程序耗尽连接数据库时,通常会导致大量资源在故障之前被耗尽,并且还可能干扰依赖于能够连接到数据库的其他应用程序和数据库状态机制。
-
鉴于以上所述,可以将连接池视为用于连接的安全阀,从而提供了针对恶意应用程序的关键保护层,该恶意程序导致整个数据库对所有其他应用程序不可用。收到此错误消息时,最好使用过多的连接来修复问题和/或适当地配置限制,而不是允许无限的溢出,而这实际上并不能解决根本的问题。
是什么导致应用程序用尽了所有可用的连接?
-
应用程序正在根据池的配置值来处理太多并发请求以完成工作 -这是最直接的原因。如果您的应用程序在允许30个并发线程的线程池中运行,并且每个线程正在使用一个连接,则如果您的池未配置为一次至少检查30个连接,则一旦应用程序接收到足够的并发请求。解决方案是提高池的限制或降低并发线程数。
-
应用程序没有将连接返回到池 -这是下一个最常见的原因,这是因为应用程序正在使用连接池,但是程序无法释放这些连接,而是使其保持打开状态。连接池以及ORM Session确实具有这样的逻辑,即当对会话和/或连接对象进行垃圾回收时,它会导致基础连接资源被释放,但是不能依赖此行为来及时释放资源。
-
发生这种情况的一个常见原因是应用程序使用ORM会话,并且没有调用Session.close()它们完成该会话的工作。解决方案是Connection通过使用适当的.close()方法或使用可用的上下文管理器之一(例如,如果使用ORM,则确保ORM会话,如果使用Core,则限制引擎绑定的对象)在工作结束时显式关闭。 “ with:”语句)以正确释放资源。
-
该应用程序正在尝试运行长时间运行的事务 -数据库事务是非常昂贵的资源,并且永远不应闲置以等待发生某些事件。如果应用程序正在等待用户按下按钮,或者结果从长时间运行的作业队列中消失,或者正在保持对浏览器的持久连接打开,则不要一直保持数据库事务处于打开状态。由于应用程序需要使用数据库并与事件进行交互,因此请在此时打开一个短暂的事务,然后将其关闭。
-
应用程序处于死锁状态 -也是此错误的常见原因,并且更难于处理,如果应用程序由于应用程序端或数据库端死锁而无法完成其连接的使用,则该应用程序可能会用尽所有可用的连接,然后导致其他请求收到此错误。死锁的原因包括:
-
使用隐式异步系统(例如gevent或eventlet),而没有正确地猴子修补所有套接字库和驱动程序,或者存在无法完全覆盖所有猴子修补的驱动程序方法的错误,或者在将异步系统用于绑定CPU的工作负载和greenlet时不太常见利用数据库资源只是等待太久而无法使用它们。对于绝大多数关系数据库操作而言,隐式或显式异步编程框架通常都不是必需的或不适当的。如果应用程序必须使用异步系统来实现某些功能,则最好将面向数据库的业务方法在将消息传递到应用程序异步部分的传统线程中运行。
-
数据库端死锁,例如行相互死锁
-
线程错误,例如相互死锁中的互斥锁,或在同一线程中调用已经锁定的互斥锁
-