TimeoutError: QueuePool 大小为 5 的限制溢出 10,连接超时,超时 30

Posted

技术标签:

【中文标题】TimeoutError: QueuePool 大小为 5 的限制溢出 10,连接超时,超时 30【英文标题】:TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30 【发布时间】:2016-09-29 22:55:31 【问题描述】:

遇到一个非常令人沮丧的错误,每当访问我的一个 api 端点时就会弹出该错误。为了提供上下文,我正在使用 SQLAlchemy 开发一个 Flask 应用程序,该应用程序将数据存储在 PostgreSQL 数据库中,以容纳 1000 个连接。

用户查询所述数据的一种方式是通过 /timeseries 端点。数据以json形式返回,由查询数据库返回的ResultProxies组装而成。

希望通过使用多线程,我可以让视图控制器为 /timeseries 调用的方法运行得更快,因为我们最初的设置需要很长时间来响应会返回大量查询的查询数据。

由于没有正确清理会话,我已经阅读了许多其他具有相同问题的帖子,但我觉得好像我已经解决了这个问题。我写的代码有什么明显的错误吗?

该应用程序使用 AWS 弹性 beanstalk 部署。

@classmethod
def timeseries_all(cls, table_names, agg_unit, start, end, geom=None):
    """
    For each candidate dataset, query the matching timeseries and push datasets with nonempty
    timeseries into a list to convert to JSON and display.

    :param table_names: list of tables to generate timetables for
    :param agg_unit: a unit of time to divide up the data by (day, week, month, year)
    :param start: starting date to limit query
    :param end: ending date to limit query
    :param geom: geometric constraints of the query

    :returns: timeseries list to display
    """

    threads = []
    timeseries_dicts = []

    # set up engine for use with threading
    psql_db = create_engine(DATABASE_CONN, pool_size=10, max_overflow=-1, pool_timeout=100)
    scoped_sessionmaker = scoped_session(sessionmaker(bind=psql_db, autoflush=True, autocommit=True))

    def fetch_timeseries(t_name):
        _session = scoped_sessionmaker()
        # retrieve MetaTable object to call timeseries from
        table = MetaTable.get_by_dataset_name(t_name)
        # retrieve ResultProxy from executing timeseries selection
        rp = _session.execute(table.timeseries(agg_unit, start, end, geom))

        # empty results will just have a header
        if rp.rowcount > 0:

            timeseries = 
                'dataset_name': t_name,
                'items': [],
                'count': 0
            

            for row in rp.fetchall():
                timeseries['items'].append('count': row.count, 'datetime': row.time_bucket.date())
                timeseries['count'] += row.count

            # load to outer storage
            timeseries_dicts.append(timeseries)

        # clean up session
        rp.close()
        scoped_sessionmaker.remove()

    # create a new thread for every table to query
    for name in table_names:
        thread = threading.Thread(target=fetch_timeseries, args=(name, ))
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    for thread in threads:
        thread.join()

    # release all connections associated with this engine
    psql_db.dispose()

    return timeseries_dicts

【问题讨论】:

那么,您是否可能只是尝试同时查询超过 15 个(或 10 个,从您的代码)表? 【参考方案1】:

我认为您正在以一种迂回的方式来解决这个问题。以下是关于充分利用您的 postgres 连接的一些建议(我已在生产中使用此配置)。

    我将使用Flask-SQLAlchemy 扩展来处理与您的 Postgres 实例的连接。如果您查看 SQLAlchemy 文档,您会发现 author highly recommends 使用它来处理数据库连接生命周期,而不是滚动您自己的生命周期。

    处理大量请求的更高效的方法是将您的 Flask 应用程序放在 wsgi 服务器后面,例如 gunicorn 或 uwsgi。这些服务器将能够生成您的应用程序的多个实例。然后,当有人点击您的端点时,您将在这些实例之间实现连接负载平衡。

    例如,如果您将 uwsgi 设置为运行 5 个进程,那么您将能够同时处理 50 个数据库连接(每个应用程序 5 个应用程序 x 10 个池)

【讨论】:

以上是关于TimeoutError: QueuePool 大小为 5 的限制溢出 10,连接超时,超时 30的主要内容,如果未能解决你的问题,请参考以下文章

Sequelize:TimeoutError:ResourceRequest 超时

除了 ConnectionError 或 TimeoutError 不起作用

LAN 上的服务器/客户端应用程序 TimeoutError

Rails 应用程序中的 Redis::TimeoutError

aiohttp asyncio.TimeoutError 从无使用 ClientSession

pymysql.err.OperationalError: (2006, "MySQL server has gone away (TimeoutError(110, 'Connection