【问题标题】:Asyncpg pool waits for all resultsAsyncpg 池等待所有结果
【发布时间】:2021-01-21 08:24:06
【问题描述】:

我使用 asyncpg 进行繁重的查询,通常需要大约 15-20 秒来计算。我正在试验池的最小和最大大小,并注意到一个奇怪的行为。当我尝试发出多个请求时,它们会同时执行,但结果会成批返回。批次的大小始终与池相同。这种行为会导致第一次响应的时间很长,比如 50 秒左右。第一批之后,我需要再等待 50 秒,才能得到其他结果。似乎 asyncpg 等待从池中收集所有结果并返回它们,而不是在结果准备好后立即返回。

有没有办法在单个请求执行后立即获得结果?也许我缺少一些设置?

有一段时间我可以保持 25 个连接,但这似乎是一种 hack,我真的不喜欢。

如果这很重要,我会使用 DSN 创建一个池。

db_pool = await asyncpg.create_pool(loop=self._loop, **params)

这是我用来向 DB 发出请求的代码:

    async def first(self, query: str, values: List, db_name: str = 'default'):
        pool = self.get_pool(db_name)

        async with pool.acquire() as conn:
            return await conn.fetchrow(query, *values)

现在我正在测试默认池大小(最大 10 个,最小 10 个)并同时发送 25 个请求。

result for 336997:  45.43796348571777 s
result for 368406:  45.43796348571777 s
result for 288307:  45.81912803649902 s
result for 283236:  46.499717235565186 s
result for 296000:  49.140310764312744 s
result for 304671:  49.20531177520752 s
result for 283685:  49.26837992668152 s
result for 283772:  49.3363881111145 s
result for 283720:  49.3753764629364 s
result for 294811:  49.39737892150879 s
result for 325604:  112.60201215744019 s
result for 336997:  112.60101222991943 s
result for 283028:  112.62509346008301 s
result for 291122:  113.41229104995728 s
result for 281105:  115.48561716079712 s
result for 304874:  115.59060764312744 s
result for 281875:  115.73372554779053 s
result for 283219:  115.73472547531128 s
result for 312094:  116.00303101539612 s
result for 312094:  116.0290174484253 s
result for 368406:  157.77449679374695 s
result for 325604:  157.77449679374695 s
result for 281932:  157.79654741287231 s
result for 290687:  157.79554748535156 s
result for 304874:  158.38678884506226 s

如果我将 max 和 min 设置为 25,当我得到这些结果时:

result for 368406:  96.23042106628418 s
result for 368406:  96.22842144966125 s
result for 283236:  97.59920930862427 s
result for 304671:  99.69211030006409 s
result for 281932:  107.54676508903503 s
result for 283685:  107.95523738861084 s
result for 281875:  108.28549408912659 s
result for 283720:  108.39060115814209 s
result for 283028:  108.388601064682 s
result for 296000:  108.44459056854248 s
result for 283772:  108.55759739875793 s
result for 291122:  108.59360837936401 s
result for 294811:  108.90663266181946 s
result for 336997:  109.07162356376648 s
result for 325604:  109.07562470436096 s
result for 325604:  109.17762279510498 s
result for 336997:  109.30463767051697 s
result for 312094:  109.40563464164734 s
result for 312094:  109.40663456916809 s
result for 281105:  109.63970899581909 s
result for 290687:  109.66070008277893 s
result for 304874:  109.66170001029968 s
result for 288307:  109.68773555755615 s
result for 304874:  109.68273568153381 s
result for 283219:  109.68573522567749 s

5/5 连接会带来糟糕的结果

result for 288307:  38.87580060958862 s
result for 325604:  38.87280225753784 s
result for 283219:  38.87380290031433 s
result for 283772:  38.98385691642761 s
result for 304671:  39.80011057853699 s
result for 368406:  94.94180464744568 s
result for 283720:  94.94180464744568 s
result for 296000:  94.98080492019653 s
result for 294811:  95.45388603210449 s
result for 283685:  95.85135459899902 s
result for 291122:  156.6862394809723 s
result for 325604:  156.68523907661438 s
result for 336997:  156.68724012374878 s
result for 304874:  156.8772156238556 s
result for 283236:  157.72206735610962 s
result for 336997:  219.94082736968994 s
result for 368406:  219.96384191513062 s
result for 312094:  220.39882922172546 s
result for 281105:  220.8170771598816 s
result for 283028:  221.18352794647217 s
result for 290687:  283.105571269989 s
result for 281932:  283.10657024383545 s
result for 304874:  283.105571269989 s
result for 281875:  283.21556425094604 s
result for 312094:  283.7060844898224 s

【问题讨论】:

  • 如果您的一项测试中最多只有 10 个连接,您如何同时发送 25 个请求?在这种情况下,至少必须连续处理一些请求。
  • 你明白 postgres 会产生一个进程来处理来自每个连接的请求/查询,是吗?因此,要并行执行 25 个查询,您必须拥有 25 个连接。您还应该担心每个查询的处理速度下降,因为您有更多的连接(从 40 秒/5 个连接的查询到 >100 秒/25 个连接的查询)。这表明存在一些正在减慢处理速度的资源的争用。这同样会影响其他应用程序对数据库进行的任何其他并发查询。
  • @Dunes 我知道如果只有 10 个连接,则不会同时处理所有 25 个请求。我想知道为什么池等待来自所有连接的结果,而不是在连接可用时立即返回结果,并在连接可用时立即开始处理新查询?为什么要等待池中的其他连接?
  • 它似乎没有在等待。如果您查看 10 个池,前 10 个结果会在 45 到 49 秒之间返回。如果它对结果进行批处理,我希望在 100 毫秒左右的窗口内看到这些时间。也许查询或数据集的某些属性意味着它具有相当统一的处理时间。

标签: python python-3.x postgresql connection-pooling asyncpg


【解决方案1】:

这是数据库方面的问题,我们不得不增加资源来解决这个问题。

【讨论】:

    【解决方案2】:

    每个查询只等待自己的结果。如果所有查询都花费了大约相同的工作量,那么它们(实际上正在运行的)都会在大约相同的时间后完成。无论如何也不是那么相似,从 45.4 到 49.4 的差值并非微不足道。如果它以某种方式故意同步它们,你会认为它会做得更好。

    有一段时间我可以保持 25 个连接,但这似乎是一种 hack,我真的不喜欢。

    你更愿意做什么?使用较小的数字?更高的?一个每分钟都在变化的随机数?您应该限制连接池。为什么 25 会是 hack,而其他数字则不会?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-08
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2017-04-29
      • 1970-01-01
      相关资源
      最近更新 更多