了解芹菜任务预取


79

我刚刚发现了有关配置选项CELERYD_PREFETCH_MULTIPLIERdocs)的信息。默认值为4,但是(我相信)我希望预取尽可能少。我现在将其设置为1,这已经足够接近我要查找的内容,但是仍然有些我不了解的事情:

  1. 为什么这样预取一个好主意?我并没有真正找到原因,除非消息队列和工作线程之间存在大量延迟(就我而言,它们当前正在同一主机上运行,​​最糟糕的是最终可能在同一数据中的不同主机上运行)中央)。该文档仅提到了缺点,但没有解释优点是什么。

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

  3. 为什么不能关闭预取?在大多数情况下,关闭性能可能不是一个好主意,但是有没有技术上的理由无法做到这一点?还是只是没有实施?

  4. 有时,此选项连接到CELERY_ACKS_LATE。例如。罗杰·胡(Roger Hu)写道«[…]通常,[用户]真正想要的是让一个工人只保留与子进程一样多的任务。但是,如果不启用较晚的确认,这是不可能的。可以在这里找到有关连接的另一个提示。有人可以解释为什么两个选项连接在一起吗?

Answers:


32
  1. 预取可以提高性能。工人无需等待来自代理的下一条消息即可处理。与代理进行一次通信并处理大量消息可提高性能。与本地内存访问相比,从代理(甚至从本地代理)获取消息的成本很高。还允许工人分批确认消息

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

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

  4. 预取允许分批确认消息。CELERY_ACKS_LATE =当邮件到达工作人员时,True阻止确认邮件


谢谢。2)好的,但是为什么有人要“没有具体限制”?3)我敢肯定,在当前任务完成之前,我仍然会看到“来自代理的任务”信息。
Henrik Heimbuerger 2013年

1
AFAIK,将预取设置为1并不等同于将其关闭。这是预取的最低可能值(同时不破坏源代码),而预取又是当前计算机中的CPU /内核数。
罗恩·克莱因

1
@RonKlein这不是CPU /内核的数量,而是您定义的Celery工人的数量(在某些情况下可以相同,但通常不一样)。同样,如果每个工作人员正在预取一个任务,然后执行它,然后预取另一个任务,这等效于关闭预取,所以恕我直言,您的声明不正确。(如果系统要让所有工作人员
忙于

3
我认为将CELERYD_PREFETCH_MULTIPLIER设置为1基本上意味着“获取”。将该值设置为> 1时,意味着预取。因此,实际上是“预取”超过1的任务。
tigeronk2

3
我已经运行一些实验,和(至少Redis的经纪人)的设置CELERYD_PREFETCH_MULTIPLIER = 1确实没有禁用预取。顾名思义,它一次只能预取一个任务。
David Wolever,2015年

28

旧问题,但仍添加我的答案以防有人帮助。我从一些初步测试中得出的理解与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绝对需要将其设置为。无论如何,我们出于其他原因将任务设置为这种方式(延迟确认)。


感谢您仍然对这个问题做出贡献!您能否添加更多细节?例如,您所写的内容-Ofair具有“不同的效果”,但效果却不同。另外,您正在CELERY_ACKS_LATE像其他人一样提拔自己,但是到目前为止,没有人能向我解释该属性与禁用预取有关。
Henrik Heimbuerger '16

我也遇到了同样的问题,使用Redis后端运行。我有4个并发任务正在运行,当一个任务开始挂起时,其他任务将等待该任务完成(这不会)-杀死该工作人员将允许其他任务恢复。我已经拥有了prefetch=1, celery_acks=True,当我添加-Ofair它时,解决了他们在等待上吊工人的问题。不幸的是,对于我来说,悬而未决的工人问题仍然没有解决,因此所有工人最终都被吊死了,但至少他们不再完全在同一时间吊死。
JiminyCricket

18

只是警告:在对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中的队列长度将立即从5降至3

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

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

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


1
正如其他答案提到的那样,如果您也进行了设置CELERY_ACKS_LATE = 1,则将有效地禁用预取。
jodag

11

我无法评论David Wolever的答案,因为我的stackcred不够高。因此,我将自己的评论作为答案,因为我想与Celery 3.1.18和Mongodb经纪人分享我的经验。我设法停止预取以下内容:

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

将CELERY_ACKS_LATE保留为默认值,该工作程序仍会预取。就像OP一样,我也没有完全掌握预取和后期ack之间的联系。我理解David所说的“ CELERY_ACKS_LATE = True可以防止在到达工作人员时确认消息”,但是我不明白为什么后期通知与预取不兼容。从理论上讲,即使未在芹菜中这样编码,预取仍将允许确认较晚的权利?


2

我作为SQS的经纪人经历了一些不同。

设置是:

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

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

使工人继续消耗工作的解决方案正在设定

CELERYD_PREFETCH_MULTIPLIER = 0

我只能推测在编写SQS传输时未考虑acks_late


我创建了处理这种情况的PR,它将在celery == 4.4.0中提供。github.com
celery/
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.