92

我刚刚发现了配置选项CELERYD_PREFETCH_MULTIPLIERdocs)。默认值为 4,但(我相信)我希望预取关闭或尽可能低。我现在将其设置为 1,这与我要查找的内容足够接近,但仍有一些我不明白的地方:

  1. 为什么预取是个好主意?我真的没有看到它的原因,除非消息队列和工作人员之间有很多延迟(在我的情况下,它们当前在同一主机上运行,​​最坏的情况可能最终在相同数据的不同主机上运行中央)。文档只提到了缺点,但没有解释优点是什么。

  2. 许多人似乎将其设置为 0,希望能够以这种方式关闭预取(我认为这是一个合理的假设)。但是,0 表示无限预取。为什么有人想要无限制的预取,这不是完全消除了您首先引入任务队列的并发/异步性吗?

  3. 为什么不能关闭预取?在大多数情况下,关闭它可能不是一个好主意,但是否有技术上的原因导致这不可能?还是只是没有实施?

  4. 有时,此选项连接到CELERY_ACKS_LATE. 例如。Roger Hu 写道«[...] 通常 [用户] 真正想要的是让工作人员只保留与子进程一样多的任务。但是,如果不启用延迟确认,这是不可能的 [...]» 我不明白这两个选项是如何连接的,以及为什么没有另一个选项是不可能的。可以在此处找到有关连接的另一个提及。有人可以解释为什么这两个选项是连接的吗?

4

5 回答 5

38
  1. 预取可以提高性能。工作人员不需要等待来自代理的下一条消息来处理。与代理通信一次并处理大量消息可以提高性能。与本地内存访问相比,从代理(甚至是本地代理)获取消息是昂贵的。工人也可以批量确认消息

  2. 预取设置为零意味着“没有特定限制”而不是无限制

  3. 将预取设置为 1 被记录为等同于将其关闭,但情况可能并非总是如此(请参阅https://stackoverflow.com/a/33357180/71522

  4. 预取允许批量确认消息。CELERY_ACKS_LATE=True 防止在消息到达工作人员时确认消息

于 2013-04-17T13:40:36.337 回答
29

老问题,但仍然添加我的答案,以防它帮助某人。我对一些初步测试的理解与 David Wolever 的回答相同。我刚刚在 celery 3.1.19 中对此进行了更多测试并且-Ofair确实有效。只是它并不意味着在工作节点级别禁用预取。这将继续发生。使用-Ofair具有不同的效果,即在池工作人员级别。总之,要完全禁用预取,请执行以下操作:

  1. CELERYD_PREFETCH_MULTIPLIER = 1
  2. CELERY_ACKS_LATE = True在全局级别或任务级别设置
  3. -Ofair在启动工人时使用
  4. 如果将并发设置为 1,则不需要步骤 3。如果您想要更高的并发性,那么第 3 步对于避免在可能运行长时间运行的任务的节点中备份任务至关重要。

添加更多细节:

我发现工作节点默认情况下总是会预取。您只能通过使用来控制它预取的任务数CELERYD_PREFETCH_MULTIPLIER。如果设置为 1,它将仅预取与节点中池工作程序(并发)数量一样多的任务。因此,如果您有并发 = n,则节点预取的最大任务数将为 n。

如果没有这个-Ofair选项,对我来说发生的事情是,如果一个池工作进程正在执行一个长时间运行的任务,节点中的其他工作进程也将停止处理节点已经预取的任务。通过使用-Ofair,情况发生了变化。即使节点中的一个工作人员正在执行长时间运行的任务,其他工作人员也不会停止处理并继续处理节点预取的任务。所以我看到了两个级别的预取。一个在工作节点级别。另一个在个体工人层面。为我使用-Ofair似乎在工人级别禁用它。

ACKS_LATE什么关系?ACKS_LATE = True意味着只有在任务成功时才会确认任务。如果没有,我想它会在工人收到它时发生。在预取的情况下,任务首先由工作人员接收(从日志中确认),但稍后会执行。我刚刚意识到预取的消息显示在 rabbitmq 的“未确认消息”下。所以我不确定是否True绝对需要将其设置为。无论如何,出于其他原因,我们将任务设置为这种方式(延迟确认)。

于 2016-06-08T10:30:04.293 回答
20

只是一个警告:在我使用 redis 代理 + Celery 3.1.15 进行测试时,我读过的所有关于CELERYD_PREFETCH_MULTIPLIER = 1禁用预取的建议都被证明是错误的。

为了证明这一点:

  1. CELERYD_PREFETCH_MULTIPLIER = 1
  2. 排队 5 个任务,每个任务都需要几秒钟(例如,time.sleep(5)
  3. 开始看Redis中任务队列的长度:watch redis-cli -c llen default

  4. 开始celery worker -c 1

  5. 请注意,Redis 中的队列长度会立即从 下降53

CELERYD_PREFETCH_MULTIPLIER = 1 不阻止预取,它只是将预取限制为每个队列 1 个任务。

-Ofair尽管文档说了什么,也不会阻止预取

除了修改源代码之外,我还没有找到任何完全禁用预取的方法。

于 2015-10-26T23:07:59.913 回答
13

我无法评论 David Wolever 的答案,因为我的 stackcred 不够高。因此,我将我的评论框定为答案,因为我想分享我使用 Celery 3.1.18 和 Mongodb 代理的经验。我设法通过以下方式停止预取:

  1. 添加CELERYD_PREFETCH_MULTIPLIER = 1到芹菜配置
  2. 添加CELERY_ACKS_LATE = True到芹菜配置
  3. 使用以下选项启动 celery worker:--concurrency=1 -Ofair

将 CELERY_ACKS_LATE 保留为默认值,工作人员仍会预取。就像 OP 一样,我没有完全掌握预取和延迟确认之间的联系。我理解大卫所说的“CELERY_ACKS_LATE=True 阻止在消息到达工作人员时确认消息”,但我不明白为什么迟到的确认与预取不兼容。从理论上讲,预取仍然允许正确地确认迟到 - 即使没有在 celery 中这样编码?

于 2015-10-29T21:23:03.600 回答
1

使用 SQS 作为代理,我经历了一些不同的事情。

设置是:

CELERYD_PREFETCH_MULTIPLIER = 1
ACKS_ON_FAILURE_OR_TIMEOUT=False
CELERY_ACKS_LATE = True
CONCURRENCY=1

任务失败(引发异常)后,由于本地和远程队列均未确认消息,因此工作人员变得不可用。

使工人继续消耗工作的解决方案是设置

CELERYD_PREFETCH_MULTIPLIER = 0

我只能推测在编写 SQS 传输时没有考虑到 acks_late

于 2019-11-20T16:13:37.683 回答