18

我正在寻找推荐的解决方案来解决 celerybeat 作为 celery/rabbitmq 部署的单点故障。到目前为止,通过搜索网络,我没有找到任何有意义的东西。

就我而言,每天一次的定时调度程序会启动一系列可能运行半天或更长时间的作业。由于只能有一个 celerybeat 实例,如果它或运行它的服务器发生问题,将不会运行关键作业。

我希望已经有一个可行的解决方案,因为我不能是唯一需要可靠(集群或类似)调度程序的人。如果我不需要的话,我不想求助于某种数据库支持的调度程序。

4

1 回答 1

7

celery github repo 中有一个关于此的未解决问题。不知道他们是否正在努力。

作为一种解决方法,您可以为任务添加一个锁,以便一次只运行一个特定 PeriodicTask 的实例。

就像是:

if not cache.add('My-unique-lock-name', True, timeout=lock_timeout):
    return

搞清楚锁定超时很好,很棘手。如果不同的 celerybeats 会尝试在不同的时间运行它们,我们将使用 0.9 * task run_every seconds。0.9 只是为了留下一些余量(例如,当 celery 稍微落后于计划一次时,它会按计划进行,这将导致锁仍然处于活动状态)。

然后你可以在所有机器上使用 celerybeat 实例。每个 celerybeat 实例的每个任务都将排队,但其中只有一个任务会完成运行。

任务仍然会以这种方式尊重 run_ever - 最坏的情况:任务将以 0.9*run_every 速度运行。

这种情况的一个问题:如果任务已排队但未在预定时间处理(例如,因为队列处理器不可用) - 那么锁定可能被放置在错误的时间,导致可能有 1 个下一个任务根本无法运行。要解决这个问题,无论任务或多或少准时,您都需要某种检测机制。

不过,在生产中使用时,这不应该是常见的情况。

另一种解决方案是继承 celerybeat Scheduler 并覆盖它的 tick 方法。然后在处理任务之前为每个刻度添加一个锁。这确保只有具有相同周期性任务的 celerybeats 不会多次排队相同的任务。每个滴答声(赢得比赛条件的人)只有一个 celerybeat 将排队任务。在一个 celerybeat 下降,下一个滴答声另一个将赢得比赛。

这当然可以与第一种解决方案结合使用。

当然,要使缓存后端正常工作,需要为所有服务器复制和/或共享缓存后端。

这是一个老问题,但我希望它可以帮助任何人。

于 2012-10-18T15:28:19.560 回答