带有RabbitMQ的芹菜4在工人启动时非常缓慢地缓冲ETA任务

时间:2019-03-10 01:15:22

标签: python rabbitmq celery celeryd

上下文

我最近开始尝试将Celery从3.1.25升级到4.2.1。我们正在运行Python 2.7.6,RabbitMQ(3.6)后端和pyamqp驱动程序。

我们在禁用pidbox的情况下运行celery,并带有--without-mingle--without-gossip--without-heartbeat选项。

我们有一个仅包含一种类型任务的队列:一个ETA任务,其执行时间在将来很远(几天)。每个任务的执行时间均小于1毫秒,并且很少“到期”。在大多数情况下,这些工作人员会以ETA状态坐下来缓冲ETA任务,等待新任务到达或偶尔执行。

几个工人(并发1,前叉)在该队列上侦听。这些工人将CELERYD_PREFETCH_MULTIPLIER设置为50。

通常,当这些工作者重新启动时,RabbitMQ中的任务将以非常短的顺序重新交付。在几分钟或更短的时间内:所有任务都离开“就绪”状态,并由工作人员“保持不败”状态。

以前,当我们将CELERYD_PREFETCH_MULTIPLIER设置为1时,工作人员需要很长时间来缓冲任务(通过工作人员逐渐增加其QoS,然后RabbitMQ随后将这些任务分配给工作人员并进行过渡)进入未锁定状态)。将其设置为50后,RabbitMQ中的10,000个任务队列的重新缓冲过程如下所示:

enter image description here

所有任务都被缓冲后,Celery立即开始执行(非常少的)预计到达时间到期的任务。

问题

从celery 3.1.25升级到4.2.1之后,重新启动ETA工作者时,Celery需要很长时间才能增加其QoS缓冲区大小,以使所有消息进入“未确认”状态(并且进入其内部堆队列以进行ETA检查)。需要花费很长时间才能错过某些任务的预计到达时间。

Celery 4的QoS窗口(尽管确实稳定地增加)比版本3增长得慢得多。

我可以在笔记本电脑上本地复制这种情况(队列中充满了预计到达时间为几天的ETA任务),也可以在生产中使用。 Celery 3似乎偶尔会增加其QoS和睡眠,但不会持续很长时间。 Celery 4同样提高了其QoS,但似乎更频繁地睡眠,并且睡眠时间更长。即使在调试模式下,工人睡觉时也不会发出任何信息。

在该测试中,Celery 4的行为如下所示:

enter image description here

(消息的到达时间是20:02,这是我在开始工作程序并开始测试之前用ETA任务填充队列的原因。

在这些行为之间唯一发生变化的是Celery的版本。

这会导致生产中的问题,因为重新启动工时(例如由于代码部署),虽然工作人员可能在几分钟之内不可用,但只有非常深的仅ETA的队列可能需要数小时才能重新交付给工作人员。在这段时间内,过去的ETA可能无法执行。

问题

  • 为什么从仅包含ETA任务的队列中进行基于预取的任务交付,而Celery 4中的未来到达时间比Celery 3中的要慢得多?
  • 如何在不降级的情况下恢复Celery 3的行为?

我尝试过的东西

  • 通过增加并行度来解决问题。仅生产ETA的队列通常运行时,消息总数超过100k,并并行消耗4个进程(每个进程是另一台主机上的--concurrency=1 Celery worker)。在Celery 3上,有4名工人进行的总的停机/延迟-ETA时间约为3分钟。在Celery 4上,我们尝试将工作人员增加到64位,但是在就绪状态下,队列到达0条消息仍然花费了一个多小时。
  • 从芹菜来源看,速率限制可能与这种情况有关。用CELERY_DISABLE_RATE_LIMITS运行Celery对行为没有影响。
  • 我已经尝试将受影响的工作人员上的CELERYD_PREFETCH_MULTIPLIER设置为0。这就解决了问题(任务重新缓冲的速度甚至比Celery 3还要快),但引入了一个更严重的问题:一些工作人员经常崩溃并耗尽内存,直到系统在不同主机上的不同使用者之间达到平衡。这会导致监视失败和大量噪音,除非没有其他选择,否则我不希望依靠“竞争”的工作人员尽快消耗消息。至少在Celery 3上,使用较高的乘数使我们能够在集群中的所有使用者之间或多或少均匀地分布ETA待处理消息。
    • 我尝试切换回-OFast调度程序(Celery 4更改了默认值)。这没有效果。
    • 更改CELERYD_TIMER_PRECISION的值也无效。

0 个答案:

没有答案