了解芹菜任务预取

Hen*_*ger 67 python celery celeryd

我刚刚发现了配置选项CELERYD_PREFETCH_MULTIPLIER(docs).默认值为4,但(我相信)我希望预取或尽可能低.我现在把它设置为1,这足够接近我正在寻找的东西,但仍有一些我不明白的东西:

  1. 为什么这个预取是一个好主意?除非消息队列和工作人员之间存在大量延迟(在我的情况下,他们当前在同一主机上运行,​​最糟糕的情况可能最终在同一数据中的不同主机上运行),我真的没有理由看到它.中央).文档仅提到了缺点,但未能解释其优点.

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

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

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

mhe*_*her 24

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

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

  3. 将预取设置为1记录为相当于将其关闭,但情况可能并非总是如此(请参阅/sf/answers/2335002631/)

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

  • 我进行了一些实验,并且(至少使用 Redis 代理)设置 `CELERYD_PREFETCH_MULTIPLIER = 1` 不会*禁用预取。它只是——顾名思义——一次只预取一项任务。 (5认同)
  • 我认为CELERYD_PREFETCH_MULTIPLIER设置为1基本上意味着'抓取'.当值设置为> 1时,隐含预取.因此,实际上超过1的任务正在"预取". (3认同)
  • AFAIK,将预取设置为 1 **不**相当于将其关闭。它是预取的最低可能值(同时不破坏源代码),而预取又是当前机器中的 CPU/核心数。 (2认同)
  • @RonKlein这不是CPU/核心的数量,而是您定义的Celery工作人员的数量(在某些情况下可能相同,但通常不是)。另外,如果每个工作人员都预取一个任务,然后执行它,然后预取另一个任务,这相当于关闭预取,所以恕我直言,您的陈述是不正确的。(如果系统想让所有工作人员都完成任务,则系统必须始终预取与工作人员数量一样多的任务。) (2认同)

ksr*_*ini 23

老问题,但仍然添加我的答案,以防它有助于某人.我从一些初步测试中得到的理解与David Wolever的回答相同.我刚刚在芹菜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绝对需要设置它.无论如何,由于其他原因,我们的任务设置如此(晚期).


Dav*_*ver 14

只是一个警告:在我使用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,尽管文档中说什么,也不会阻止预取.

如果没有修改源代码,我还没有找到任何完全禁用预取的方法.

  • 正如其他答案所提到的,如果您还设置了“CELERY_ACKS_LATE = 1”,那么您将有效地禁用预取。 (2认同)

Pau*_*gen 9

我不能评论David Wolever的答案,因为我的stackcred不够高.所以,我已经把我的评论作为一个答案,因为我想与Celery 3.1.18和Mongodb经纪人分享我的经验.我设法停止预取以下内容:

  1. 添加CELERYD_PREFETCH_MULTIPLIER = 1到芹菜配置
  2. 添加CELERY_ACKS_LATE = True到芹菜配置
  3. 通过选项启动芹菜工人: --concurrency=1 -Ofair

将CELERY_ACKS_LATE保留为默认值,工作人员仍然会预取.就像OP一样,我没有完全掌握预取和后期之间的联系.我理解大卫所说的"CELERY_ACKS_LATE = True可以防止在他们到达工作人员时确认消息",但我不明白为什么迟到的acks与prefetch不兼容.从理论上讲,预取仍然可以让你迟到 - 即使在芹菜中没有这样编码?