我最近开始尝试将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个任务队列的重新缓冲过程如下所示:
所有任务都被缓冲后,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的行为如下所示:
(消息的到达时间是20:02,这是我在开始工作程序并开始测试之前用ETA任务填充队列的原因。
在这些行为之间唯一发生变化的是Celery的版本。
这会导致生产中的问题,因为重新启动工时(例如由于代码部署),虽然工作人员可能在几分钟之内不可用,但只有非常深的仅ETA的队列可能需要数小时才能重新交付给工作人员。在这段时间内,过去的ETA可能无法执行。
--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
的值也无效。